#pragma name "Gold Rush"
#pragma description "Variant on Treasure Hunt using regenerating coins instead of gems. If you roast another player, you gain 25 coins and your victim loses all their coins. The number of coins you must bring to the exit to win constantly decreases. Playable in any level--if there is no exit, players win automatically."
#include "ArtificialArrow.asc"
void onLevelLoad() {
uint numberOfCoins = 0;
for (int x = jjLayerWidth[4]; --x >= 0;)
for (int y = jjLayerHeight[4]; --y >= 0;) {
OBJECT::Object objectToGenerate;
int delay = 0;
uint8 event = jjEventGet(x,y);
if (event == OBJECT::GENERATOR)
event = jjParameterGet(x,y, 0,8);
switch (event) {
case OBJECT::REDGEM:
case OBJECT::FLICKERGEM:
case OBJECT::PURPLEGEM:
case OBJECT::RECTREDGEM:
objectToGenerate = OBJECT::SILVERCOIN;
numberOfCoins += 1;
delay = 8;
break;
case OBJECT::RECTGREENGEM:
case OBJECT::GREENGEM:
case OBJECT::GEMSTOMP:
objectToGenerate = OBJECT::GOLDCOIN;
numberOfCoins += 5;
delay = 14;
break;
case OBJECT::RECTBLUEGEM:
case OBJECT::BLUEGEM:
objectToGenerate = OBJECT::GOLDCOIN;
numberOfCoins += 5;
delay = 7;
break;
case OBJECT::GEMRING:
case OBJECT::SUPERGEM:
objectToGenerate = OBJECT::GOLDCOIN;
numberOfCoins += 5;
delay = 8;
break;
case OBJECT::GEMCRATE:
case OBJECT::GEMBARREL:
jjEventSet(x,y, 0);
continue;
default:
if (event == AREA::WARP && jjParameterGet(x,y, 8,8) != 0)
jjEventSet(x,y, event = AREA::EOL);
if (EndAreas.find(event) >= 0) {
EndLocations.insertLast(x * 32);
EndLocations.insertLast(y * 32);
jjEventSet(x,y, AREA::EOL); //simpler to treat them all the same
jjAddObject(OBJECT::BEES, x*32 + 16, y*32 + 16, 0, CREATOR::LEVEL, CoinWarp);
}
continue;
}
jjEventSet(x,y, OBJECT::GENERATOR);
jjParameterSet(x,y, 0,8, objectToGenerate);
jjParameterSet(x,y, 8,8, delay);
}
if (numberOfCoins < 60) { //probably not a treasure hunt level... go again, but with laxer standards!
for (int x = jjLayerWidth[4]; --x >= 0;)
for (int y = jjLayerHeight[4]; --y >= 0;) {
uint8 event = jjEventGet(x,y);
const uint param = jjParameterGet(x,y, 0,8);
if (event == OBJECT::GENERATOR)
event = param;
if (event <= OBJECT::GUN9AMMO3 && event >= OBJECT::ICEAMMO3) { //regular ammo pickup
int generatorObjectID;
if (jjIsServer) {
generatorObjectID = jjAddObject(OBJECT::AIRBOARDGENERATOR, x * 32 + 15, y * 32 + 15, 0,CREATOR::LEVEL, function(obj) { //use OBJECT::AIRBOARDGENERATOR to avoid uid conflicts
if (obj.age == 0) { //initializing
obj.age = 1;
} else { //first real tick, we don't want to run BEHAVIOR::GENERATOR until this because it would result in servers and clients having different objectIDs
obj.age = 0;
const uint x = uint(obj.xOrg) >> 5, y = uint(obj.yOrg) >> 5, param = jjParameterGet(x,y, 0,8);
jjParameterSet(x,y, 0,8, OBJECT::SILVERCOIN); //object to be generated
obj.behavior = BEHAVIOR::GENERATOR;
obj.behave(); //read bitmap and start generating coins
jjParameterSet(x,y, 0,8, param); //for anything else on this tile
}
});
} else {
jjParameterSet(x,y, 0,8, OBJECT::SILVERCOIN); //object to be generated
generatorObjectID = jjAddObject(OBJECT::AIRBOARDGENERATOR, x * 32 + 15, y * 32 + 15, 0,CREATOR::LEVEL, BEHAVIOR::GENERATOR); //use OBJECT::AIRBOARDGENERATOR to avoid uid conflicts
jjParameterSet(x,y, 0,8, param);
}
}
}
}
}
uint Points = 0;
void onLevelBegin() {
if (jjIsServer) {
for (uint i = 0; i < 32; ++i)
if (jjPlayers[i].isActive && !jjPlayers[i].isIdle)
Points += 1;
//jjDebug(Points + " points up for grabs...");
if (!(jjGameMode == GAME::BATTLE && jjGameCustom == GAME::NOCUSTOM))
jjChat("/battle");
if (jjPlayers[0].isSpectating && !jjPlayers[0].isIdle)
jjChat("/forcespectate 1 off");
jjPrint("**** " + jjLevelName + " (" + jjLevelFileName + ") GoldRush.mut");
} else {
jjSTREAM packet;
packet.push(true);
for (int i = 0; i < jjLocalPlayerCount; ++i)
packet.push(uint8(jjLocalPlayers[i].playerID));
jjSendPacket(packet);
}
}
const array<uint8> EndAreas = { AREA::EOL, AREA::WARPEOL, AREA::WARPSECRET, OBJECT::EOLPOST, OBJECT::BONUSPOST, OBJECT::CTFBASE };
const array<string> Places = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth", "twenty-first", "twenty-second", "twenty-third", "twenty-fourth", "twenty-fifth", "twenty-sixth", "twenty-seventh", "twenty-eighth", "twenty-ninth", "thirtieth"};
uint Place = 0;
uint8 MaxScore = jjMaxScore > 50 ? jjMaxScore : 50;
void onMain() {
if (jjIsServer) {
if ((jjGameState == GAME::STARTED || jjGameState == GAME::OVERTIME)) {
if (MaxScore > 15 and jjActiveGameTicks % 140 == 0)
MaxScore -= 1;
if (jjActiveGameTicks % 70 == 0) {
jjSTREAM packet;
packet.push(MaxScore);
for (uint8 i = 0; i < 32; ++i)
if (jjPlayers[i].isInGame) {
packet.push(i);
packet.push(uint16(jjPlayers[i].coins));
}
jjSendPacket(packet);
}
uint numberOfIngamePlayers = 0;
int lastIngamePlayer = -1;
for (uint i = 0; i < 32; ++i) {
const jjPLAYER@ player = jjPlayers[i];
if (player.isInGame) {
const int coins = player.coins;
if (coins >= int(MaxScore) && (EndLocations.isEmpty() || jjEventGet(uint(player.xPos) >> 5, uint(player.yPos) >> 5) == AREA::EOL)) {
jjChat("/forcespectate " + (i+1) + " on");
jjAlert("|||" + player.nameUnformatted + (Place < 30 ? (" wins " + Places[Place++] + " place!") : " wins!"), true, STRING::MEDIUM);
jjPrint("**** " + player.nameUnformatted + ": " + coins + " coins (out of " + MaxScore + " coins)");
/*if (Points > 1) {
jjPrint("**** " + Points + " points for " + player.name);
Points -= 1;
} else {
jjPrint("**** 1 point for " + player.name);*/
//}
} else {
numberOfIngamePlayers += 1;
lastIngamePlayer = i;
}
} else if (player.isActive && player.isConnecting) {
numberOfIngamePlayers += 1;
lastIngamePlayer = i;
}
}
if (numberOfIngamePlayers <= 1 && jjGameConnection == GAME::ONLINE) {
if (numberOfIngamePlayers == 1) {
jjAlert(jjPlayers[lastIngamePlayer].nameUnformatted + " places |last", true, STRING::MEDIUM);
jjPrint("**** " + jjPlayers[lastIngamePlayer].nameUnformatted + ": " + jjPlayers[lastIngamePlayer].coins + " coins (out of " + MaxScore + " coins)");
// jjPrint("**** " + Points + " point for " + jjPlayers[lastIngamePlayer].name);
}
jjChat("/stop");
}
}
} else {
if (jjActiveGameTicks % 70 == 0) {
jjSTREAM packet;
packet.push(false);
for (int i = 0; i < jjLocalPlayerCount; ++i)
if (jjLocalPlayers[i].isInGame) {
packet.push(uint8(jjLocalPlayers[i].playerID));
packet.push(uint16(jjLocalPlayers[i].coins));
}
jjSendPacket(packet);
}
}
}
void onPlayerDraw(jjPLAYERDRAW& draw) {
if (draw.name) {
const jjPLAYER@ player = draw.player;
const bool enough = player.coins >= int(MaxScore);
jjDrawResizedSpriteFromCurFrame(player.xPos - 8, player.yPos - 47, jjObjectPresets[enough ? OBJECT::GOLDCOIN : OBJECT::SILVERCOIN].curFrame, 0.5, 0.5, SPRITE::NORMAL,0, -100);
jjDrawString(player.xPos - 3, player.yPos - 45, (enough ? "||||" : "|||||||") + "x" + player.coins, STRING::SMALL, STRING::NORMAL, 0, -100);
}
}
bool onDrawGameModeHUD(jjPLAYER@ player, jjCANVAS@ canvas) {
if (player !is null) {
const bool enough = player.coins >= int(MaxScore);
//canvas.drawRectangle(0,0, 172, 34, 15);
//canvas.drawRectangle(0,0, 170, 32, 0);
canvas.drawSprite(12,17, ANIM::PICKUPS, enough ? 37 : 84, jjGameTicks >> 3);
canvas.drawString(30, 13, (enough ? "||||" : "|||||||") + player.coins + "/" + MaxScore, STRING::MEDIUM);
if (enough) {
if (!EndLocations.isEmpty())
canvas.drawString(0x8000, jjSubscreenHeight - 49, "FIND EXIT", STRING::MEDIUM, STRING::SPIN);
} else
canvas.drawString(10, 36, "§1||Need " + (MaxScore - player.coins) + " more", STRING::SMALL, STRING::NORMAL,0, SPRITE::TRANSLUCENTPALSHIFT);
} else
canvas.drawString(30, 13, "|||||||" + MaxScore, STRING::MEDIUM);
return true;
}
void onReceive(jjSTREAM &in packet, int fromClientID) {
uint8 playerID;
uint16 coins;
if (jjIsServer) {
bool gameStart;
packet.pop(gameStart);
while (!packet.isEmpty()) {
packet.pop(playerID);
if (jjPlayers[playerID].clientID == fromClientID) {
if (gameStart) {
jjChat("/forcespectate " + (playerID + 1) + " off");
} else {
packet.pop(coins);
jjPlayers[playerID].coins = coins;
}
} else { //bad packet
return; //meh, whatever
}
}
} else {
packet.pop(MaxScore);
while (!packet.isEmpty()) {
packet.pop(playerID);
packet.pop(coins);
if (!jjPlayers[playerID].isLocal)
jjPlayers[playerID].coins = coins;
}
}
}
array<int> EndLocations;
bool onExit = false;
uint TimeTopLeft = 0;
void onPlayer(jjPLAYER@ player) {
if (!EndLocations.isEmpty()) { //at least one exit
const bool enough = player.coins >= int(MaxScore);
const bool wasOnExit = onExit;
onExit = jjEventGet(uint(player.xPos) >> 5, uint(player.yPos) >> 5) == AREA::EOL;
if (!wasOnExit && onExit && !enough)
player.testForCoins(MaxScore);
else if (!onExit)
ArtificialArrow::DrawArrow(EndLocations, player, enough ? SPRITE::SINGLEHUE : SPRITE::TRANSLUCENTSINGLEHUE, 72);
} //else everywhere is an exit, no need to do HUD stuff pointing at one
if (player.health > 0 && int(player.xPos) / 32 <= 0 && int(player.yPos) / 32 <= 0 && player.warpID == 0) {
if (++TimeTopLeft % 280 == 250) {
for (int x = jjLayerWidth[4]; --x >= 0;)
for (int y = jjLayerHeight[4]; --y >= 0;) {
const uint8 event = jjEventGet(x,y);
if (event == AREA::JAZZSTART || event == AREA::MPSTART) {
player.warpToTile(x,y);
return;
}
}
}
} else TimeTopLeft = 0;
}
void onRoast(jjPLAYER@ victim, jjPLAYER@ killer) {
if (victim !is killer && killer.isLocal)
killer.coins += 25;
}
void CoinWarp(jjOBJ@ obj) {
if (obj.state == STATE::START) {
obj.state = STATE::ROTATE;
obj.curFrame = jjObjectPresets[OBJECT::SILVERCOIN].curFrame;
obj.playerHandling = HANDLING::PARTICLE;
obj.bulletHandling = HANDLING::IGNOREBULLET;
//obj.lightType = LIGHT::RING2;
//obj.light = 10;
}
//if (jjTileGet(3, int(obj.xOrg / 32), int(obj.yOrg / 32)) == 0) //no foreground
for (int i = 0; i < 8; ++i) {
const int timer = (jjGameTicks<<2) + i*128;
const float distance = 32 + jjSin(jjRenderFrame<<3) * 8;
jjDrawRotatedSpriteFromCurFrame(obj.xPos + jjSin(timer) * distance, obj.yPos + jjCos(timer) * distance, ((i & 1) == 0) ? obj.curFrame : obj.curFrame + 10, timer + 512,
//1.0f, 1.0f, SPRITE::SINGLEHUE, jjLocalPlayers[0].teamRed ? 24 : 32, 3);
1.0f, 1.0f, SPRITE::NORMAL, 0, 3);
}
}