Compare commits

..

No commits in common. "main" and "v1.0" have entirely different histories.
main ... v1.0

8 changed files with 31 additions and 245 deletions

3
.gitignore vendored
View File

@ -1,4 +1,3 @@
build/
*.hex
slangin.hex
.ccls-cache/
res/candywar/

View File

@ -2,10 +2,6 @@
DrugWars (DopeWars) clone for the [Arduboy](https://www.arduboy.com).
You hit the streets of New York with $2000 in your pocket and a $5000 debt to the loan shark. Buy low and sell high to pay off your debt as quickly as possible, then spend the rest of the time getting rich to earn a high score. Each day has the possibility for a random event that could help or hinder your progress, and if you hold on to too much product Officer Hardass and his deputies might notice.
You can play either the classic 30 day mode, or an extended mode where you go for 60 days, and high scores for each mode are persisted to the EEPROM so they'll save between reboots.
[Reference implementation.](https://gist.github.com/mattmanning/1002653/b7a1e88479a10eaae3bd5298b8b2c86e16fb4404)
## Building
@ -25,10 +21,6 @@ arduino-cli upload -b arduino:avr:leonardo -p /dev/ttyACM1 slangin.hex
Your port path (`-p` argument) may differ depending on your system.
## CandyWar
Run `res/candywar.sh` to generate an alternate version of the game with replaced title images and strings if you have delicate sensibilities.
## Resources
Font libraries used:
@ -36,11 +28,3 @@ Font libraries used:
- [Font4x6](https://github.com/filmote/Font4x6)
Slightly modified to add missing comma and apostrophe characters.
## Screenshots
![slangin-title.png](https://f000.backblazeb2.com/file/img-rdsm-ca/2022/06/22/slangin-title.png)
![slangin-menu.png](https://f000.backblazeb2.com/file/img-rdsm-ca/2022/06/22/slangin-menu.png)
![slangin-drugs.png](https://f000.backblazeb2.com/file/img-rdsm-ca/2022/06/22/slangin-drugs.png)
![slangin-buy.png](https://f000.backblazeb2.com/file/img-rdsm-ca/2022/06/22/slangin-buy.png)
![slangin-hardass.png](https://f000.backblazeb2.com/file/img-rdsm-ca/2022/06/22/slangin-hardass.png)

View File

@ -160,36 +160,3 @@ void buildDrugMenu(const long extra[6]) {
menuCols = true;
menuSmall = col1Max + col2Max > 22;
}
int getMenuBackOut() {
// this whole thing could have been done so much better :(
// i suck at C++
switch (sGameState) {
case STATE_SELL_MENU:
case STATE_BORROW_INPUT:
case STATE_WITHDRAW_INPUT:
return 1;
case STATE_INVENTORY:
case STATE_HIGH_SCORES:
return 2;
case STATE_JET_MENU:
return 3;
case STATE_SHARK_MENU:
return 4;
case STATE_BANK_MENU:
return 5;
case STATE_BUY_QTY_INPUT:
case STATE_SELL_QTY_INPUT:
return sCurrentDrug;
case STATE_INFO_DIALOG:
switch (sPreviousGameState) {
case STATE_BUY_MENU:
case STATE_SELL_MENU:
return sCurrentDrug;
default:
return 0;
}
default:
return 0;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 950 B

View File

@ -1,80 +0,0 @@
#!/usr/bin/env bash
# Slangin' -> CandyWar
rm -rf candywar
mkdir candywar
cp ../*.ino candywar/
cp -r ../src candywar/
mv candywar/slangin.ino candywar/candywar.ino
for file in candywar/*.ino; do
sed -i "s/Slangin'/CandyWar/g" "$file"
sed -i "s/Hit the Streets/Hit the Sweets/" "$file"
sed -i "s/Drugs/Candy/g" "$file"
sed -i "s/drugs/candy/g" "$file"
sed -i "s/Loan Shark/Rich Buddy/g" "$file"
sed -i "s/Cocaine/P.Sugar/g" "$file"
sed -i "s/Heroine/Hershey/gi" "$file"
sed -i "s/Acid/Aero/gi" "$file"
sed -i "s/Weed/Mars/g" "$file"
sed -i "s/Speed/Sours/g" "$file"
sed -i "s/Ludes/Lolly/g" "$file"
sed -i "s/ludes/lolly/g" "$file"
sed -i "s/Trenchcoat/Candy Sack/g" "$file"
sed -i "s/trenchcoat/candy sack/g" "$file"
sed -i "s/more pockets/more space/" "$file"
sed -i "s/Pigs/Moms/gi" "$file"
sed -i "s/doctor to sew you/dentist to fix/" "$file"
sed -i 's/"up?"/"your teeth?"/' "$file"
sed -i "s/You hallucinate on the/You eat it all but/" "$file"
sed -i "s/wildest trip of your/forget to brush your/" "$file"
sed -i "s/life, stumble onto the/teeth. They all rot/" "$file"
sed -i "s/subway tracks, and get/and you can't eat/" "$file"
sed -i "s/creamed by a train./solid food anymore./" "$file"
sed -i "s/raid!!!!/bake-off!!!!/" "$file"
sed -i "s/Moms made a big/Powdered sugar/" "$file"
sed -i "s/coke bust!/shortage!/" "$file"
sed -i "s/Addicts are/Chocoholics are/" "$file"
sed -i "s/Rival dealers are/Kids at school/" "$file"
sed -i "s/selling cheap/are selling cheap/" "$file"
sed -i "s/Officer Hardass/Your Mother/g" "$file"
sed -i 's/" of his"/" of her"/' "$file"
sed -i "s/deputies are/friends are/" "$file"
sed -i "s/baretta/sleep spray/" "$file"
sed -i "s/\.44 magnum/stink spray/" "$file"
sed -i "s/saturday night/Mom repellant/" "$file"
sed -i "s/special for/spray for/" "$file"
sed -i "s/some weed/some gum/" "$file"
sed -i "s/that smells/that looks/" "$file"
sed -i "s/like good stuff/mostly unchewed/" "$file"
sed -i "s/smoke it/eat it/" "$file"
sed -i "s/You were mugged/You gave a bit/" "$file"
sed -i "s/in the subway!/to charity!/" "$file"
sed -i "s/on a dead dude/in a lunch box/" "$file"
sed -i "s/guns/spray/g" "$file"
sed -i "s/You killed one/A Mom gave up/" "$file"
sed -i "s/You killed all of/They all gave up!/" "$file"
sed -i "s/them! You found /You snatched /" "$file"
sed -i "s/dollars on Officer/bucks from purses/" "$file"
sed -i "s/Hardass' carcass/during the chase/" "$file"
sed -i "s/firing at/nagging/" "$file"
sed -i "s/You're dead/You're caught/g" "$file"
sed -i "s/Guns/Spray/" "$file"
sed -i "s/A Fight/A Spray/" "$file"
sed -i "s/0x00, 0x00, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x78, 0x07, 0x06, 0x78, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x00,/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0xe8, 0xc4, 0x82, 0x02, 0x03, 0x3f, 0x3f, 0x0f, 0x87, 0x82, 0xc2, 0xc4, 0xc8, 0xf0, 0xc0,/" "$file"
sed -i "s/0x00, 0x00, 0x03, 0x3c, 0xc1, 0x02, 0x04, 0x08, 0x10, 0x20, 0xc0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xc0, 0x20, 0x10, 0x08, 0x04, 0x04, 0xc2, 0x39, 0x07, 0x00, 0x00,/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x70, 0x88, 0xa8, 0x0f, 0xf1, 0x81, 0x01, 0x81, 0xc1, 0xe1, 0xf0, 0xfc, 0xf0, 0x00, 0x81, 0x81, 0x43, 0x27, 0x1f, 0x07,/" "$file"
sed -i "s/0x38, 0x50, 0x90, 0x90, 0x90, 0x23, 0x24, 0x48, 0x50, 0x60, 0x81, 0x26, 0x08, 0xe7, 0x00, 0x90, 0xe7, 0x08, 0x26, 0x01, 0x60, 0x50, 0x48, 0x26, 0xa1, 0x90, 0x90, 0x90, 0x50, 0x30,/0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0xa1, 0x56, 0x2c, 0x14, 0x34, 0x22, 0x41, 0x76, 0x08, 0x0d, 0x09, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/" "$file"
sed -i "s/0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x22, 0x32, 0x2a, 0x24, 0x22, 0x10, 0x0a, 0x08, 0x0c, 0x08, 0x12, 0x21, 0x24, 0x2a, 0x32, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/0x30, 0x28, 0x14, 0x0a, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/" "$file"
sed -i "s/Bronx/Sweet Suites/" "$file"
sed -i "s/Ghetto/Ice Cream Rd/" "$file"
sed -i "s/Central Park/Chocoland/" "$file"
sed -i "s/Manhatten/Gummy Forest/" "$file"
sed -i "s/Coney Island/Soda Swamp/" "$file"
sed -i "s/Brooklyn/Candy Castle/" "$file"
done
arduino-cli compile -b arduino:avr:leonardo -e candywar/
cp candywar/build/arduino.avr.leonardo/candywar.ino.hex candywar.hex
sim_arduboy -k 1073741906,1073741905,1073741904,1073741903,104,116 -p 6 ./candywar.hex

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 B

View File

@ -5,7 +5,6 @@ License: WTFPL
*/
#include <Arduboy2.h>
#include <EEPROM.h>
#include "src/Font3x5.h"
#include "src/Font4x6.h"
@ -15,7 +14,6 @@ Font3x5 font3x5 = Font3x5();
enum GameState {
STATE_TITLE = 0,
STATE_HIGH_SCORES,
STATE_TURN_MENU,
STATE_JET_MENU,
STATE_BUY_MENU,
@ -77,27 +75,21 @@ const uint8_t PROGMEM spriteWeed[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x22, 0x32, 0x2a, 0x24, 0x22, 0x10, 0x0a, 0x08, 0x0c, 0x08, 0x12, 0x21, 0x24, 0x2a, 0x32, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t eepStart = EEPROM_STORAGE_SPACE_START + 1;
/**************/
/* game state */
/**************/
bool screenInitialized;
GameState sGameState;
GameState sPreviousGameState;
short sMaxDays;
short sCurrentDay;
int sCurrentDay;
long sDrugPrices[6];
short sCurrentDrug;
int sCurrentDrug;
long sCurrentQty;
long sQtyMax;
long sLastDebounce = 0;
int sDebounceCount = 0;
short sDebounceCount = 0;
bool sAlreadyBorrowed;
short sPigs = 0;
// default high scores
long s30High = 100000;
long s60High = 200000;
int sPigs = 0;
/****************/
/* player state */
@ -111,12 +103,11 @@ int pCapacity;
int pHealth;
long pInventory[6];
String menu[6];
String menu[8];
int menuLength = 0;
bool menuCols = false;
bool menuSmall = false;
int menuSelected = 0;
int menuBackOut = 0;
String dialog[5];
int dialogLength;
@ -127,23 +118,11 @@ bool dialogSmall = false;
/***********************/
void setup() {
arduboy.boot();
arduboy.bootLogoSpritesOverwrite();
arduboy.setFrameRate(15);
arduboy.initRandomSeed();
sGameState = STATE_TITLE;
screenInitialized = false;
// read high scores from eeprom
char check[5];
EEPROM.get(eepStart, check);
if (strcmp(check, "slng") == 0) {
EEPROM.get(eepStart + 5, s30High);
EEPROM.get(eepStart + 9, s60High);
} else {
EEPROM.put(eepStart, "slng");
EEPROM.put(eepStart + 5, s30High);
EEPROM.put(eepStart + 9, s60High);
}
arduboy.begin();
}
void loop() {
@ -158,12 +137,11 @@ void loop() {
if (!screenInitialized) {
arduboy.clear();
menuSelected = menuBackOut;
menuBackOut = 0;
menuSelected = 0;
// if we're entering the turn menu on day 31 then game is over instead
if (sGameState == STATE_TURN_MENU
&& sCurrentDay >= sMaxDays) {
&& sCurrentDay >= 31) {
sGameState = STATE_GAME_OVER;
}
@ -171,27 +149,18 @@ void loop() {
case STATE_TITLE:
Sprites::drawOverwrite(0, 0, spriteWeed, 0);
Sprites::drawOverwrite(98, 0, spriteWeed, 0);
arduboy.setCursor(42, 10);
arduboy.setCursor(42, 15);
arduboy.print(F("Slangin'"));
font3x5.setCursor(103, 58);
font3x5.print(F("v1.2.0"));
menu[0] = F("Hit the Streets");
menu[1] = F("Extended Game");
menu[2] = F("High Scores");
menuLength = 3;
menuSmall = true;
font3x5.setCursor(113, 58);
font3x5.print(F("v1.0"));
menu[0] = F("Hit the Streets!!");
menuLength = 1;
menuSmall = false;
menuCols = false;
drawMenu(menuSmall, menuCols, menuLength, menu);
drawMenuIndicator(menuSelected, menuSmall, menuCols, menuLength, menu, false);
break;
case STATE_HIGH_SCORES:
drawDialog();
drawMoney(10, 19, s30High);
drawMoney(10, 39, s60High);
sPreviousGameState = STATE_TITLE;
break;
case STATE_TURN_MENU:
drawStatusBar();
drawTitle(lookupLocation(pLocation));
@ -227,7 +196,6 @@ void loop() {
buildDrugMenu(sDrugPrices);
drawMenu(menuSmall, menuCols, menuLength, menu);
drawMenuIndicator(menuSelected, menuSmall, menuCols, menuLength, menu, false);
drawDrugsOwned(menuSelected);
break;
case STATE_JET_MENU: {
@ -379,33 +347,17 @@ void loop() {
break;
case STATE_GAME_OVER: {
int score = floor(sqrt((pSavingsAmount + pMoney - pLoanAmount) / 31.5));
if (score > 100) score = 100;
dialog[0] = "";
dialog[1] = " Game over!";
dialog[2] = " Your score: ";
dialog[2] += String(score);
dialog[3] = " out of 100.";
dialogSmall = false;
dialogLength = 3;
dialogLength = 4;
sPreviousGameState = STATE_TITLE;
pMoney += pSavingsAmount - pLoanAmount;
for (int i = 0; i < 6; i++) {
pMoney += pInventory[i] * sDrugPrices[i];
}
if (pMoney < 0) {
pMoney = 0;
}
bool newHigh = sMaxDays == 31 ? pMoney > s30High : pMoney > s60High;
dialog[0] = F("Game over! Score:");
dialog[1] = F("");
dialog[2] = newHigh ? F("Old ") : F("");
dialog[2] += F("High Score:");
drawDialog();
drawMoney(10, 19, pMoney);
drawMoney(10, 39, sMaxDays == 31 ? s30High : s60High);
if (newHigh) {
if (sMaxDays == 31) {
s30High = pMoney;
EEPROM.put(eepStart + 5, s30High);
} else {
s60High = pMoney;
EEPROM.put(eepStart + 9, s60High);
}
}
break;
}
@ -478,19 +430,14 @@ void loop() {
sGameState == STATE_SHARK_MENU ||
sGameState == STATE_BANK_MENU) {
screenInitialized = false;
menuBackOut = getMenuBackOut();
sGameState = STATE_TURN_MENU;
}
}
drawMenuIndicator(menuSelected, menuSmall, menuCols, menuLength, menu, false);
if (sGameState == STATE_BUY_MENU || sGameState == STATE_SELL_MENU) {
drawDrugsOwned(menuSelected);
}
}
break;
}
case STATE_INVENTORY:
case STATE_HIGH_SCORES:
case STATE_INFO_DIALOG:
case STATE_DID_WEED_DIALOG_1:
case STATE_DID_WEED_DIALOG_2:
@ -574,20 +521,13 @@ void loop() {
break;
}
screenInitialized = false;
menuBackOut = getMenuBackOut();
sGameState = sPreviousGameState;
} else {
const unsigned long currentMillis = millis();
const long incAmount = sGameState == STATE_BUY_QTY_INPUT ||
const int incAmount = sGameState == STATE_BUY_QTY_INPUT ||
sGameState == STATE_SELL_QTY_INPUT ? 1 : 10;
if (currentMillis - sLastDebounce > (sDebounceCount < 2 ? 500 : sDebounceCount < 21 ? 100 : 0)) {
const long incMult = sDebounceCount < 100
? 1 : sDebounceCount < 125
? 10 : sDebounceCount < 150
? 100 : sDebounceCount < 175
? 1000
: 10000;
if (sDebounceCount < 1000) sDebounceCount++;
if (currentMillis - sLastDebounce > (sDebounceCount < 2 ? 500 : 100)) {
if (sDebounceCount < 2) sDebounceCount++;
if (arduboy.pressed(UP_BUTTON)) {
sLastDebounce = currentMillis;
if (sCurrentQty <= sQtyMax - incAmount) sCurrentQty += incAmount;
@ -595,8 +535,7 @@ void loop() {
drawQtyInputTotal();
} else if (arduboy.pressed(RIGHT_BUTTON)) {
sLastDebounce = currentMillis;
if (sCurrentQty + incAmount * 10 * incMult <= sQtyMax)
sCurrentQty += incAmount * 10 * incMult;
if (sCurrentQty <= sQtyMax - incAmount * 10) sCurrentQty += incAmount * 10;
else sCurrentQty = sQtyMax;
drawQtyInputTotal();
} else if (arduboy.pressed(DOWN_BUTTON)) {
@ -606,8 +545,7 @@ void loop() {
drawQtyInputTotal();
} else if (arduboy.pressed(LEFT_BUTTON)) {
sLastDebounce = currentMillis;
if (sCurrentQty >= incAmount * 10 * incMult)
sCurrentQty -= incAmount * 10 * incMult;
if (sCurrentQty >= incAmount * 10) sCurrentQty -= incAmount * 10;
else sCurrentQty = 0;
drawQtyInputTotal();
} else {
@ -720,12 +658,3 @@ void drawFightPrompt() {
arduboy.drawCircle(67, 58, 5, WHITE);
arduboy.drawCircle(103, 58, 5, WHITE);
}
void drawDrugsOwned(Drug drug) {
// wipe old indicator
arduboy.fillRect(60, 9, 68, 12, BLACK);
String numStr = String(pInventory[drug]);
font3x5.setCursor(92 - numStr.length() * 4, 13);
font3x5.print("You own ");
font3x5.print(numStr);
}

View File

@ -5,7 +5,7 @@ Author: Rudis Muiznieks
License: WTFPL
*/
void initializeNewGame(int days) {
void initializeNewGame() {
sGameState = STATE_TURN_MENU;
pMoney = 2000;
pLoanAmount = 5000;
@ -19,7 +19,6 @@ void initializeNewGame(int days) {
pInventory[i] = 0;
}
sMaxDays = days + 1;
sCurrentDay = 0;
incrementDay(false); // start on day 1
}
@ -199,18 +198,7 @@ void handleMenuAction() {
case STATE_TITLE:
switch (menuSelected) {
case 0: // new game
initializeNewGame(30);
break;
case 1: // extended game
initializeNewGame(60);
break;
case 2: // high scores
dialog[0] = F("Normal Game:");
dialog[1] = F("");
dialog[2] = F("Extended Game:");
dialogSmall = false;
dialogLength = 3;
sGameState = STATE_HIGH_SCORES;
initializeNewGame();
break;
}
break;
@ -430,7 +418,6 @@ bool checkBackedOut(const bool eitherButton) {
if (arduboy.justPressed(B_BUTTON) ||
(eitherButton && arduboy.justPressed(A_BUTTON))) {
screenInitialized = false;
menuBackOut = getMenuBackOut();
sGameState = sPreviousGameState;
return true;
}
@ -442,7 +429,7 @@ int playerCapacityRemaining() {
for (int i = 0; i < 6; i++) {
qty += pInventory[i];
}
//qty += pGuns * 5; // already accounted for
qty += pGuns * 5;
return pCapacity - qty;
}