0

I am making a "Clicker-Game". It's my first real game that I'm doing alongside school. I got all of the game code complete but I want to have a loop in the background that adds geldps(money per second) after every second. I tried threads but I don't really understand it and we won't learn that until next year, so I´m asking, if anyone can either tell me a better way to make a loop in the background that runs independent from the main program, and can just add geldps to geld every second. Thanks. PS: I am sorry for the German variables. Ask me if you don't know what sth means or anything, and it´s probably not very well organised and everything.

#include <stdio.h>

int geldps=0,geld=0;

int main()
{
 int stand=0, oil=0, Mine=0, Bank=0,standzahl=100, Minezahl=500, Bankzahl=1000, oilzahl=10000, Werkzeug=0, Werkzeugzahl=10;
char input, input2;
float faktor;
do
{
    system("cls");
    faktor=1+Werkzeug/10;
    printf("%c%c%c%c%c%c%c%c%c%c%c\n",201,205,205,205,205,205,205,205,205,205,187);
    printf("   %d$\n",geld);
    printf("%c%c%c%c%c%c%c%c%c%c%c\n",200,205,205,205,205,205,205,205,205,205,188);
    printf(" Space to get money\n U to go to Upgrades\n Escape to leave");
    input=getch();
    if(input==32)
    {
        geld=geld+faktor;
        continue;
    }
    if(input == 117 || input == 85)
    {
        system("cls");
        do
        {
            system("cls");
            printf(" 0 - Tools(10 for 1 more Money)(%d)(%d$)\n 1 - Lemon Stands(%d)(%d$)\n 2 - Mines(%d)(%d$)\n 3 - Banks(%d)(%d$)\n 4 - Oil Refinerys(%d)(%d$)\nBackspace to go back", Werkzeug, Werkzeugzahl, stand, standzahl, Mine, Minezahl, Bank, Bankzahl, oil, oilzahl);
            input2=getch();
            if(input2== 48)
            {
                if(geld<Werkzeugzahl)
                {
                    system("cls");
                    printf("Not enough money(%d/%d$)\n",Werkzeugzahl,geld);
                    system("pause");
                    continue;
                }
                geld=geld-Werkzeugzahl;
                Werkzeug++;
                Werkzeugzahl=Werkzeugzahl+Werkzeugzahl/10;
            }
            if(input2== 49)
            {
                if(geld<standzahl)
                {
                    system("cls");
                    printf("Not enough money(%d/%d$)\n",standzahl,geld);
                    system("pause");
                    continue;
                }
                geld=geld-standzahl;
                stand++;
                standzahl=standzahl+standzahl/10;
            }
            if(input2== 50)
            {
                if(geld<Minezahl)
                {
                    system("cls");
                    printf("Not enough money(%d/%d$)\n",Minezahl,geld);
                    system("pause");
                    continue;
                }
                geld=geld-Minezahl;
                Mine++;
                Minezahl=Minezahl+Minezahl/10;
                geldps=geldps+1;
            }
            if(input2== 51)
            {
                if(geld<Bankzahl)
                {
                    system("cls");
                    printf("Not enough money(%d/%d$)\n",Bankzahl,geld);
                    system("pause");
                    continue;
                }
                geld=geld-Bankzahl;
                Bank++;
                Bankzahl=Bankzahl+Bankzahl/10;
                geldps=geldps+10;
            }
            if(input2== 52)
            {
                if(geld<oilzahl)
                {
                    system("cls");
                    printf("Not enough money(%d/%d$)\n",oilzahl,geld);
                    system("pause");
                    continue;
                }
                    geld=geld-oilzahl;
                    oil++;
                    oilzahl=oilzahl+oilzahl/10;
                    geldps=geldps+100;
                }
            }
            while(input2!=8);
        }
    }
    while(input!=27);
    return 0;
}
akshayk07
  • 2,092
  • 1
  • 20
  • 32
  • 1
    Have a look at the `alarm()` function. Still, this would raise the need to work with signals, which might end up being more complicated then learning threads. – alk Sep 17 '17 at 11:52
  • When compiling, always enable the warnings, then fix those warnings. (for `gcc`, at a minimum use: `-Wall -Wextra -pedantic -Werror -Wconversion -std=gnu11` – user3629249 Sep 17 '17 at 12:45
  • the function: `system` is found in the stdlib.h header file. so the code needs to have the statement: `#include `. The function: `getch()` is a non-standard function (can be found in ch50.h and/or ncurses.h) however, suggest using `getchar()` found in stdio.h – user3629249 Sep 17 '17 at 12:50
  • 1
    for ease of readability and understanding: 1) follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* 2) separate code blocks: (for, if, else, while, do...while, switch, case, default) via a single blank line. using the `int` values for ascii characters make the code obscure. Suggest using the actual ascii values. Ilke 'u' rather than 117, etc – user3629249 Sep 17 '17 at 12:54
  • 1
    the shell commands `cls` and `pause` are windows OS specific. Suggest using the ASCII escape commands (and even they are not universal) for clearing the screen and using `getchar()` (after emptying the stdin stream) to cause the program to wait for the user to input a key stroke, Note: `escape` does not exit a program. Perhaps you meant `` – user3629249 Sep 17 '17 at 13:05
  • Look at answers to similar question: https://stackoverflow.com/questions/1973365/threading-in-c – MrCryo Sep 17 '17 at 13:40

1 Answers1

0

update: I was procrastinating and cleaned and improved your code. At the end of this answer.

If all you need is for a number to be consistently incremented based on time, add a function that updates a value based on time.

Here's an example showing not only how to do that but also how to compartmentalize your code into functions and how to use better code formatting and variable names.

#include <stdio.h> // printf()
#include <time.h> // time()
#include <stdlib.h> // random()
#include <unistd.h> // sleep()


int updateValue(int lastValue, int amountPerSecond) {
  static time_t lastTime = -1;

  time_t currentTime = time(NULL);
  int newValue = lastValue;

  if (lastTime != -1) {
    newValue += amountPerSecond * (currentTime - lastTime);
  }
  lastTime = currentTime;

  return newValue;
}

void seedRandom() {
  // Don't use this in production code.
  srandom(time(NULL));
}

int sleepRandomly() {
  const int SLEEP_RANGE_IN_SECS = 5;
  // sleep( 0..5 seconds )
  int timeToSleep = random() % (SLEEP_RANGE_IN_SECS + 1);
  sleep(timeToSleep);
  return timeToSleep;
}

int main() {
  const int AMOUNT_PER_SECOND = 5;
  int value = 0;
  // How many times to run the loop
  int numCycles = 5;

  seedRandom();

  // Initialize the updateValue() start time
  value = updateValue(value, AMOUNT_PER_SECOND);

  while (numCycles--) {
    int amountSlept = sleepRandomly();
    int newValue = updateValue(value, AMOUNT_PER_SECOND);
    printf("Slept %d seconds.", amountSlept);
    printf("Value updated: %10d + (%d secs * %4d amount/secs) = %10d\n",
           value, amountSlept, AMOUNT_PER_SECOND, newValue);
    value = newValue;
  }

  return 0;
}

Cleaned up version of your code, and then I just kept improving it.

#include <stdio.h> // printf()
#include <string.h> // strlen()
#include <stdarg.h> // vsnprintf()
#include <unistd.h> // STDIN_FILENO
#include <sys/time.h> // gettimeofday()
#include <time.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>

// TODO: convert the menus to tables:
//       key - desc   count   cost     effect
// TODO: add all income sources in a list so it's easy to add more
//       without changing code
// TODO: the current pricing is off
// TODO: convert to C++ so we can use classes
// TODO: only use one menu, it's nicer to use

// one global value so we can ensure that we restore
// stdin's terminal settings
struct termios g_oldStdinTermios;
int g_keepGoing = 1;

typedef struct {
  int count;
  int zahl;
  int zahlIncrement;
  int geldPerSecondIncrement;
} IncomeSource;

typedef struct {
  char lastMessage[100];

  // try to avoid global variables, pass them instead
  // one variable per line
  int geld;
  int geldPerSecond;
  int geldPerClick;

  IncomeSource werkzeug;
  IncomeSource stand;
  // Use consistent capitalization: sound be "mine"
  IncomeSource mine;
  IncomeSource bank;
  IncomeSource oil;
} Values;

void setLastMessage(Values *values, const char *fmt, ...) {
  va_list ap;
  va_start(ap, fmt);
  (void) vsnprintf(values->lastMessage, sizeof(values->lastMessage), fmt, ap);
  va_end(ap);
}

void clearLastMessage(Values *values) {
  // clear lastMessage after valid choice
  values->lastMessage[0] = '\0';
}

void initializeValues(Values *values) {
  clearLastMessage(values);

  // use spaces around assignment and operators
  values->geldPerSecond = 0;
  values->geld = 10000;
  // count, cost, cost increment (1/n), geldPerSecond increment
  values->werkzeug = (IncomeSource){0, 10, 10, 0};
  // BUG: number of stands doesn't increase geld per second
  //      or geld per click
  values->stand = (IncomeSource){0, 100, 10, 0};
  values->mine = (IncomeSource){0, 500, 10, 1};
  values->bank = (IncomeSource){0, 1000, 10, 10};
  values->oil = (IncomeSource){0, 10000, 10, 100};

  values->geldPerClick = 1 + values->werkzeug.count / 10;
}

void clearScreen() {
  // use ANSI escape sequences
  const char *ANSI_MOVE_TO_1_1 = "\x1B[1;1H";
  const char *ANSI_CLEAR_SCREEN = "\x1B[2J";
  printf("%s%s", ANSI_CLEAR_SCREEN, ANSI_MOVE_TO_1_1);
}

char upcase(char c) {
  if (c < 'a' || c > 'z') {
    return c;
  }
  return 'A' + (c - 'a');
}

void setNonBlockingBufferingStdinTermios() {
  struct termios new_;
  tcgetattr(STDIN_FILENO, &g_oldStdinTermios);
  new_ = g_oldStdinTermios;
  new_.c_lflag &= ~ICANON;
  tcsetattr(STDIN_FILENO, TCSANOW, &new_);
}

void restoreStdinTermios() {
  tcsetattr(STDIN_FILENO, TCSANOW, &g_oldStdinTermios);
}

long getElapsedTimeInMs(struct timeval *start) {
  struct timeval now;
  gettimeofday(&now, NULL);
  // in microseconds
  long elapsed = ((now.tv_sec - start->tv_sec) * 1000000
                  + now.tv_usec - start->tv_usec);
  return elapsed / 1000;
}

char getCharacter() {
  struct timeval start;
  gettimeofday(&start, NULL);

  char input = -1;
  while (read(STDIN_FILENO, &input, 1) == -1
         && errno == EAGAIN
         && getElapsedTimeInMs(&start) < 500) {
  }

  return upcase(input);
}

void updateGeld(Values *values) {
  static time_t lastTime = -1;

  time_t currentTime = time(NULL);
  if (lastTime != -1) {
    values->geld += values->geldPerSecond * (currentTime - lastTime);
  }
  lastTime = currentTime;
}

void printHeader(Values *values) {
  const char *UPPER_LEFT = "\u2554";
  const char *UPPER_RIGHT = "\u2557";
  const char *LOWER_LEFT = "\u255a";
  const char *LOWER_RIGHT = "\u255d";
  const char *HORIZONTAL = "\u2550";
  const char *VERTICAL = "\u2551";

  updateGeld(values);

  // Automatically expand the box as the size
  // of geld grows.
  const int BORDER_WIDTH = 3;
  char geldStr[20];
  snprintf(geldStr, sizeof(geldStr), "$ %d", values->geld);

  // Move code used more than once into its own function
  clearScreen();

  printf("%s", UPPER_LEFT);
  for (int i = 0; i < (2 * BORDER_WIDTH + strlen(geldStr)); i++) {
    printf("%s", HORIZONTAL);
  }
  printf("%s\n", UPPER_RIGHT);

  // use spaces around commas
  printf("%s   %s   %s   %s\n",
         VERTICAL, geldStr, VERTICAL, values->lastMessage);

  printf("%s", LOWER_LEFT);
  for (int i = 0; i < (2 * BORDER_WIDTH + strlen(geldStr)); i++) {
    printf("%s", HORIZONTAL);
  }
  printf("%s\n", LOWER_RIGHT);
}


void upgrade(Values *values, IncomeSource *source) {
  if (values->geld < source->zahl) {
    setLastMessage(values, "Not enough money(%d/%d$)",
                   source->zahl, values->geld);
    return;
  }
  clearLastMessage(values);
  values->geld -= source->zahl;
  source->count++;
  source->zahl += source->zahl / source->zahlIncrement;
  values->geldPerSecond += source->geldPerSecondIncrement;
}

char getUpgradeInput(Values *values) {
  clearScreen();
  printHeader(values);
  printf(" 0 - Tools(10 for 1 more Money)(%d)(%d$)\t\t+%d/click\n",
         values->werkzeug.count, values->werkzeug.zahl, values->geldPerClick);
  printf(" 1 - Lemon Stands(%d)(%d$)\t\t\t+%d/sec\n",
         values->stand.count, values->stand.zahl,
         values->stand.count * values->stand.geldPerSecondIncrement);
  printf(" 2 - Mines(%d)(%d$)\t\t\t\t+%d/sec\n",
         values->mine.count, values->mine.zahl,
         values->mine.count * values->mine.geldPerSecondIncrement);
  printf(" 3 - Banks(%d)(%d$)\t\t\t\t+%d/sec\n",
         values->bank.count, values->bank.zahl,
         values->bank.count * values->bank.geldPerSecondIncrement);
  printf(" 4 - Oil Refinerys(%d)(%d$)\t\t\t+%d/sec\n",
         values->oil.count, values->oil.zahl,
         values->oil.count * values->oil.geldPerSecondIncrement);
  printf(" Q - Back to main menu\n");
  printf("> ");
  fflush(stdout);
  return getCharacter();
}

void upgradeLoop(Values *values) {
  char input = ' ';
  while (input != 'Q' && g_keepGoing) {
    input = getUpgradeInput(values);
    switch (input) {
    case '0':
      upgrade(values, &values->werkzeug);
      values->geldPerClick = 1 + values->werkzeug.count / 10;
      break;
    case '1':
      upgrade(values, &values->stand);
      break;
    case '2':
      upgrade(values, &values->mine);
      break;
    case '3':
      upgrade(values, &values->bank);
      break;
    case '4':
      upgrade(values, &values->oil);
      break;
    case 'Q':
      break;
    default:
      break;
    }
  }
}

char getMainInput(Values *values) {
  printHeader(values);

  // make this easier to read in the code...
  printf(" _ - [Space] get money\n");
  printf(" U - Upgrades\n");
  printf(" Q - Quit\n");
  printf("> ");
  fflush(stdout);
  return getCharacter();
}

void mainLoop(Values *values) {
  char input = ' ';

  // while..do is easier to read and understand than do..while
  while (input != 'Q' && g_keepGoing) {
    // Encapsulate code in functions to make your program's logic
    // easier to follow
    input = getMainInput(values);
    // Use a switch statement here and use character values
    // rather than integers
    switch (input) {
    case ' ':
      values->geld += values->geldPerClick;
      clearLastMessage(values);
      break;
    case 'U':
      upgradeLoop(values);
      clearLastMessage(values);
    case 'Q':
      break;
    default:
      break;
    }
  };
}

void sigintHandler(int signal) {
  printf("SIGINT received, cleaning up.\n");
  restoreStdinTermios();
  g_keepGoing = 0;
}

int main() {
  Values values;

  initializeValues(&values);
  setNonBlockingBufferingStdinTermios();
  signal(SIGINT, sigintHandler);

  mainLoop(&values);

  restoreStdinTermios();
  return 0;
}
Harvey
  • 5,703
  • 1
  • 32
  • 41