Author Topic: Wetspot II - C BASIC  (Read 8056 times)

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Wetspot II - C BASIC
« on: October 27, 2013, 09:10:14 AM »
I thought I would start the C BASIC conversion of the Wetspot II game. So far these changes compile and the game runs. The goal is to make this game's C code look as close to BASIC as we can. A syntax colored version of the original wetspot2.c program is attached as a PDF.

FYI - C BASIC syntax notes.

* I'm using the _ with THEN and ELSE for single IFs and simple IF/THEN/ELSE statements. I will try to keep this concept going forward with other dual purpose keywords.

then used with multi-line IF
then_ used with single line IF
else_ is the else replacement and else_if will replace the C else if.
call optional but I think it helps distinguished between a function/sub call and a C variable declaration. It's your call to use it or not.
let on-the-fly C variable assignments
incr incrementing variable
mod_ replaces the C % modulus operator
and_ replaces the C && AND operator
or_ replaces the C || OR operator
begin_for starts a FOR/NEXT loop
to_ used in FOR/NEXT
step used in FOR/NEXT
begin_for starts the FOR/NEXT loop
next ends/iterates the FOR/NEXT loop
select_case a more BASIC like substitute for the C SWITCH statement
begin_select starts a SELECT/CASE block
_to_ used in the CASE statement to indicate a range
case_else replaces the C Default: SWITCH keyword
end_case ends a CASE block
end_select ends the SELECT block

Code: [Select]
// C BASIC

#define function
#define method
#define gosub
#define call
#define let
#define incr
#define dim
#define as
#define then_
#define then {
#define else_ } else {
#define sub void
#define begin {
#define begin_if {
#define begin_function {
#define begin_sub {
#define end   }
#define end_if }
#define end_function }
#define end_sub }
#define and_ &&
#define or_ ||
#define mod_ %
#define class typedef struct
#define types typedef struct
#define methods
#define member   ->
#define addressof  &
#define has =
#define NewSpace  malloc
#define FreeSpace free
#define select_case switch
#define begin_select {
#define end_case break;
#define case_else default:
#define end_select }
#define to_ ;
#define _to_ ...
#define begin_for {
#define step ;
#define next }

#define create(A,B,C) A B=malloc((C)*sizeof(*B))
#define copy(A,B,C) CopyInts((int*)A,(int*)B,C);

// Wetspot II

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>

#include "wetspot2.h"
#include "font.h"
#include "palette.h"
#include "timer.h"
#include "logo.h"
#include "sprites.h"
#include "menu.h"
#include "world.h"
#include "input.h"
#include "sound.h"

/*
COMMON SHARED Game AS GameType
COMMON SHARED Player() AS PlayerType
COMMON SHARED Enemy() AS EnemyType
COMMON SHARED Object() AS ObjectType
COMMON SHARED Block() AS BlockType
COMMON SHARED Shot() AS ShotType
COMMON SHARED Death() AS DeathType
COMMON SHARED Cel() AS INTEGER
COMMON SHARED Blocked AS INTEGER
*/

dim as SDL_Surface *screen;
dim as SDL_Surface *gamescreen;
dim as SDL_Surface *theend;
dim as Uint8 *keys;
dim as GAMETYPE Game;
dim as PLAYERTYPE Player[2];
dim as ENEMYTYPE Enemy[MAXENEMIES];
dim as OBJECTTYPE Object[MAXOBJS];
dim as BLOCKTYPE Block[MAXBLOCKS];
dim as SHOTTYPE Shot[MAXSHOTS];
dim as DEATHTYPE Death[2];
dim as CELL cell[12][20];
dim as int Blocked;


/*
SUB CheckScore (PlayerNum)
' Checks if the player has gained enough points for an extra life
IF Player(PlayerNum).score >= Player(PlayerNum).nextextra THEN
  IF Player(PlayerNum).nextextra = 30000 THEN Player(PlayerNum).nextextra = 0
  Player(PlayerNum).nextextra = Player(PlayerNum).nextextra + 100000
  Player(PlayerNum).lives = Player(PlayerNum).lives + 1
  PlaySound 7
END IF
*/
sub CheckScore(int PlayerNum)
begin_sub
  if(Player[PlayerNum].score >= Player[PlayerNum].nextextra) then
    if(Player[PlayerNum].nextextra == 30000) then_ Player[PlayerNum].nextextra = 0;
    Player[PlayerNum].nextextra += 100000;
    incr Player[PlayerNum].lives++;
    call PlaySound(7);
  end_if
end_sub

/*
DIM SHARED dx(4) AS INTEGER, dy(4) AS INTEGER
' direction can be: 0 = right, 1 = up, 2 = left, 3 = down, 4 = nowhere
DATA 0,1,-1,0,0,-1,1,0,0,0
' Gets axis dx/dy increase/decrease in each direction
FOR i = 0 TO 4
  READ dx(i), dy(i)
NEXT i
*/
dim as int dx[5] = {0, -1, 0, 1, 0};
dim as int dy[5] = {1, 0, -1, 0, 0};

call int GetFreeObject();
call void KillEnemy(int);

/*
SUB CheckStatus
' Checks game status and other minor game features
' Finds if all the players are dead; in that case, ends the game loop
IF Game.players = 0 THEN
  IF Player(0).dead = TRUE THEN Game.status = 400: Player(0).dead = 2
ELSE
  IF Player(0).dead = TRUE THEN
    Player(0).dead = 2
    IF Player(0).dead >= 2 AND Player(1).dead >= 2 THEN Game.status = 400
  END IF
  IF Player(1).dead = TRUE THEN
    Player(1).dead = 2
    IF Player(0).dead >= 2 AND Player(1).dead >= 2 THEN Game.status = 400
  END IF
END IF
' Randomly adds a bonus object on the screen (if possible)
IF Game.objects < 3 AND Game.status <> -501 THEN
  IF Game.status < 1 AND Game.time > 15 THEN
    IF INT(RND(1) * 100) = 0 THEN
      FOR i = 0 TO MAXOBJS
        IF Object(i).typ = 0 THEN EXIT FOR
      NEXT i
      Object(i).x = INT(RND(1) * 20)
      Object(i).y = INT(RND(1) * 12)
      GetBlockInfo Cel(Object(i).x, Object(i).y)
      IF st = 0 THEN
        Object(i).typ = 26 + INT(RND(1) * 8)
        Object(i).time = 0
        IF INT(RND(1) * 3) = 0 THEN
          xi = INT(RND(1) * 20): yi = INT(RND(1) * 12)
          GetBlockInfo Cel(xi, yi)
          IF rd > 0 THEN Object(i).typ = rd
          IF Game.mode = DEMO AND Object(i).typ = 14 THEN Object(i).typ = 0
        END IF
        IF INT(RND(1) * 3) = 0 THEN Object(i).typ = INT(RND(1) * 33) + 1
        Game.objects = Game.objects + 1
      END IF
    END IF
  END IF
END IF
SELECT CASE Game.status
CASE -500 TO -3
  ' The enemies are blocked by the clock
  Game.status = Game.status + 1
  IF Game.status = -2 THEN
    ' Resumes the enemies
    Game.status = 0
    IF Game.time < 16 THEN
      ChangePal 0
    ELSE
      ChangePal -1
    END IF
  END IF
CASE -2
  ' Do the lightnings
  FOR i = 0 TO 80
    DrawScreen
  NEXT i
  Game.status = 0
  FOR i = 0 TO MAXENEMIES
    IF Enemy(i).typ > 0 THEN KillEnemy i
  NEXT i
  ChangePal -1
CASE -1
  ' Do the earthquake
  Game.status = 0
  FOR i = 0 TO 100
    WAIT &H3DA, 8, 8: WAIT &H3DA, 8
    BlastCopy VARSEG(Buffer(0)), VARPTR(Buffer(0)), &HA000, ((i MOD 3) * 320)
  NEXT i
  FOR i = 0 TO MAXENEMIES
    IF Enemy(i).typ > 0 THEN KillEnemy i
  NEXT i
CASE IS > 0
  Game.status = Game.status + 1
END SELECT
*/
sub CheckStatus()
begin_sub
  if(Game.players == 1) then
    if(Player[0].dead == TRUE) then
      Game.status = 400;
      Player[0].dead = 2;
    end_if
  else_
    if(Player[0].dead == TRUE) then
      Player[0].dead = 2;
      if(Player[0].dead >= 2 and_ Player[1].dead >= 2) then_ Game.status = 400;
    end_if
    if(Player[1].dead == TRUE) then
      Player[1].dead = 2;
      if(Player[0].dead >= 2 and_ Player[1].dead >= 2) then_ Game.status = 400;
    end_if
  end_if
  if(Game.objects < 3 and_ Game.status != -501) then
    if(Game.status < 1 and_ Game.time > 15) then
      if(rand() mod_ 100 == 0) then  //INT(RND(1) * 100)
        let int i = GetFreeObject();
        Object[i].x = rand() mod_ 20; //INT(RND(1) * 20)
        Object[i].y = rand() mod_ 12; //INT(RND(1) * 12)
        if(cell[Object[i].y][Object[i].x].st == 0) then
          Object[i].typ = 26 + rand() mod_ 8; //INT(RND(1) * 8)
          Object[i].time = 0;
          if(rand() mod_ 2 == 0) then //INT(RND(1) * 3)
            let int xi = rand() mod_ 20; //INT(RND(1) * 20):
            let int yi = rand() mod_ 12; //INT(RND(1) * 12)
            if(cell[yi][xi].rd > 0) then_ Object[i].typ = cell[yi][xi].rd;
            if(Game.mode == DEMO and_ Object[i].typ == 14) then_ Object[i].typ = 0;
          end_if
          if(rand() mod_ 3 == 0) then_ Object[i].typ = rand() mod_ 33 + 1;
          incr Game.objects++;
        end_if
      end_if
    end_if
  end_if

  select_case (Game.status)
  begin_select
    case -500 _to_ -3:
      // The enemies are blocked by the clock
      incr Game.status++;
      if(Game.status == -2) then
        // Resumes the enemies
        Game.status = 0;
        if(Game.time < 16) then
          //ChangePal 0
        else_
          //ChangePal -1
        end_if
      end_if
      end_case
    case -2:
      // Do the lightnings
      Game.status = 0;
      for(int i = 0 to_ i < 80 step i++)
      begin_for
        call DrawScreen();
      next
      for(int i = 0 to_ i < MAXENEMIES step i++)
      begin_for
        if(Enemy[i].typ > 0) then_ call KillEnemy(i);
      next
      //ChangePal -1
      end_case
    case -1:
      // Do the earthquake
      Game.status = 0;
      /*for(int i = 0 TO 100
        WAIT &H3DA, 8, 8: WAIT &H3DA, 8
        BlastCopy VARSEG(Buffer(0)), VARPTR(Buffer(0)), &HA000, ((i MOD 3) * 320)
      NEXT i*/
      for(int i = 0 to_ i < MAXENEMIES step i++)
      begin_for
        if(Enemy[i].typ > 0) then_ call KillEnemy(i);
      next
      end_case
    case_else
      if(Game.status > 0) then_ incr Game.status++;
  end_select

The last functions isn't finished (closed) yet. (working on it)
« Last Edit: October 28, 2013, 01:11:49 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #1 on: October 28, 2013, 11:46:10 AM »
I wanted update (bump) everyone with where I'm at with the C BASIC conversion of the Wetspot II game.

Here is a list of C BASIC syntax that is usable. I'm counting on Charles to do the fine tuning.

  • IF/THEN/ELSE
  • FOR/NEXT
  • SELECT/CASE
  • FUNCTION/SUB
« Last Edit: October 28, 2013, 01:28:23 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
C BASIC - UPPER CASE KEYWORDS
« Reply #2 on: October 28, 2013, 02:28:30 PM »
I have switched to using upper case keywords for C BASIC.  Going to upper case allowed me to not have to use the _ attribute for keywords. I think it makes the code easier to read and more BASIC like.

Note: Single line IF's use the THEN_DO keyword and multi-line IF's use the standard THEN.

Code: [Select]
// C BASIC

#define FUNCTION
#define METHOD
#define GOSUB
#define CALL
#define LET
#define INCR
#define DIM
#define AS
#define IF if
#define THEN_DO
#define THEN {
#define ELSE } else {
#define SUB void
#define BEGIN {
#define BEGIN_IF {
#define BEGIN_FUNCTION {
#define BEGIN_SUB {
#define END   }
#define END_IF }
#define END_FUNCTION }
#define END_SUB }
#define AND &&
#define OR ||
#define MOD %
#define class typedef struct
#define types typedef struct
#define methods
#define member   ->
#define addressof  &
#define has =
#define NewSpace  malloc
#define FreeSpace free
#define SELECT_CASE switch
#define BEGIN_SELECT {
#define CASE case
#define _TO_ ...
#define END_CASE break;
#define CASE_ELSE default:
#define END_SELECT }
#define FOR for
#define TO ;
#define BEGIN_FOR {
#define STEP ;
#define NEXT }

#define create(A,B,C) A B=malloc((C)*sizeof(*B))
#define copy(A,B,C) CopyInts((int*)A,(int*)B,C);

// Wetspot II

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>

#include "wetspot2.h"
#include "font.h"
#include "palette.h"
#include "timer.h"
#include "logo.h"
#include "sprites.h"
#include "menu.h"
#include "world.h"
#include "input.h"
#include "sound.h"

/* <<< QB45 >>>
COMMON SHARED Game AS GameType
COMMON SHARED Player() AS PlayerType
COMMON SHARED Enemy() AS EnemyType
COMMON SHARED Object() AS ObjectType
COMMON SHARED Block() AS BlockType
COMMON SHARED Shot() AS ShotType
COMMON SHARED Death() AS DeathType
COMMON SHARED Cel() AS INTEGER
COMMON SHARED Blocked AS INTEGER
*/

DIM AS SDL_Surface *screen;
DIM AS SDL_Surface *gamescreen;
DIM AS SDL_Surface *theend;
DIM AS Uint8 *keys;
DIM AS GAMETYPE Game;
DIM AS PLAYERTYPE Player[2];
DIM AS ENEMYTYPE Enemy[MAXENEMIES];
DIM AS OBJECTTYPE Object[MAXOBJS];
DIM AS BLOCKTYPE Block[MAXBLOCKS];
DIM AS SHOTTYPE Shot[MAXSHOTS];
DIM AS DEATHTYPE Death[2];
DIM AS CELL cell[12][20];
DIM AS int Blocked;

/* <<< QB45 >>>
SUB CheckScore (PlayerNum)
' Checks if the player has gained enough points for an extra life
IF Player(PlayerNum).score >= Player(PlayerNum).nextextra THEN
  IF Player(PlayerNum).nextextra = 30000 THEN Player(PlayerNum).nextextra = 0
  Player(PlayerNum).nextextra = Player(PlayerNum).nextextra + 100000
  Player(PlayerNum).lives = Player(PlayerNum).lives + 1
  PlaySound 7
END IF
*/

SUB CheckScore(int PlayerNum)
BEGIN_SUB
  IF(Player[PlayerNum].score >= Player[PlayerNum].nextextra) THEN
    IF(Player[PlayerNum].nextextra == 30000) THEN_DO Player[PlayerNum].nextextra = 0;
    Player[PlayerNum].nextextra += 100000;
    INCR Player[PlayerNum].lives++;
    CALL PlaySound(7);
  END_IF
END_SUB

/* <<< QB45 >>>
DIM SHARED dx(4) AS INTEGER, dy(4) AS INTEGER
' direction can be: 0 = right, 1 = up, 2 = left, 3 = down, 4 = nowhere
DATA 0,1,-1,0,0,-1,1,0,0,0
' Gets axis dx/dy increase/decrease in each direction
FOR i = 0 TO 4
  READ dx(i), dy(i)
NEXT i
*/

DIM AS int dx[5] = {0, -1, 0, 1, 0};
DIM AS int dy[5] = {1, 0, -1, 0, 0};

CALL int GetFreeObject();
CALL void KillEnemy(int);

/* <<< QB45 >>>
SUB CheckStatus
' Checks game status and other minor game features
' Finds if all the players are dead; in that case, ends the game loop
IF Game.players = 0 THEN
  IF Player(0).dead = TRUE THEN Game.status = 400: Player(0).dead = 2
ELSE
  IF Player(0).dead = TRUE THEN
    Player(0).dead = 2
    IF Player(0).dead >= 2 AND Player(1).dead >= 2 THEN Game.status = 400
  END IF
  IF Player(1).dead = TRUE THEN
    Player(1).dead = 2
    IF Player(0).dead >= 2 AND Player(1).dead >= 2 THEN Game.status = 400
  END IF
END IF
' Randomly adds a bonus object on the screen (if possible)
IF Game.objects < 3 AND Game.status <> -501 THEN
  IF Game.status < 1 AND Game.time > 15 THEN
    IF INT(RND(1) * 100) = 0 THEN
      FOR i = 0 TO MAXOBJS
        IF Object(i).typ = 0 THEN EXIT FOR
      NEXT i
      Object(i).x = INT(RND(1) * 20)
      Object(i).y = INT(RND(1) * 12)
      GetBlockInfo Cel(Object(i).x, Object(i).y)
      IF st = 0 THEN
        Object(i).typ = 26 + INT(RND(1) * 8)
        Object(i).time = 0
        IF INT(RND(1) * 3) = 0 THEN
          xi = INT(RND(1) * 20): yi = INT(RND(1) * 12)
          GetBlockInfo Cel(xi, yi)
          IF rd > 0 THEN Object(i).typ = rd
          IF Game.mode = DEMO AND Object(i).typ = 14 THEN Object(i).typ = 0
        END IF
        IF INT(RND(1) * 3) = 0 THEN Object(i).typ = INT(RND(1) * 33) + 1
        Game.objects = Game.objects + 1
      END IF
    END IF
  END IF
END IF
SELECT CASE Game.status
CASE -500 TO -3
  ' The enemies are blocked by the clock
  Game.status = Game.status + 1
  IF Game.status = -2 THEN
    ' Resumes the enemies
    Game.status = 0
    IF Game.time < 16 THEN
      ChangePal 0
    ELSE
      ChangePal -1
    END IF
  END IF
CASE -2
  ' Do the lightnings
  FOR i = 0 TO 80
    DrawScreen
  NEXT i
  Game.status = 0
  FOR i = 0 TO MAXENEMIES
    IF Enemy(i).typ > 0 THEN KillEnemy i
  NEXT i
  ChangePal -1
CASE -1
  ' Do the earthquake
  Game.status = 0
  FOR i = 0 TO 100
    WAIT &H3DA, 8, 8: WAIT &H3DA, 8
    BlastCopy VARSEG(Buffer(0)), VARPTR(Buffer(0)), &HA000, ((i MOD 3) * 320)
  NEXT i
  FOR i = 0 TO MAXENEMIES
    IF Enemy(i).typ > 0 THEN KillEnemy i
  NEXT i
CASE IS > 0
  Game.status = Game.status + 1
END SELECT
*/

SUB CheckStatus()
BEGIN_SUB
  IF(Game.players == 1) THEN
    IF(Player[0].dead == TRUE) THEN
      Game.status = 400;
      Player[0].dead = 2;
    END_IF
  ELSE
    IF(Player[0].dead == TRUE) THEN
      Player[0].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
    IF(Player[1].dead == TRUE) THEN
      Player[1].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
  END_IF
  IF(Game.objects < 3 AND Game.status != -501) THEN
    IF(Game.status < 1 AND Game.time > 15) THEN
      IF(rand() MOD 100 == 0) THEN  //INT(RND(1) * 100)
        LET int i = GetFreeObject();
        Object[i].x = rand() MOD 20; //INT(RND(1) * 20)
        Object[i].y = rand() MOD 12; //INT(RND(1) * 12)
        IF(cell[Object[i].y][Object[i].x].st == 0) THEN
          Object[i].typ = 26 + rand() MOD 8; //INT(RND(1) * 8)
          Object[i].time = 0;
          IF(rand() MOD 2 == 0) THEN //INT(RND(1) * 3)
            LET int xi = rand() MOD 20; //INT(RND(1) * 20):
            LET int yi = rand() MOD 12; //INT(RND(1) * 12)
            IF(cell[yi][xi].rd > 0) THEN_DO Object[i].typ = cell[yi][xi].rd;
            IF(Game.mode == DEMO AND Object[i].typ == 14) THEN_DO Object[i].typ = 0;
          END_IF
          IF(rand() MOD 3 == 0) THEN_DO Object[i].typ = rand() MOD 33 + 1;
          INCR Game.objects++;
        END_IF
      END_IF
    END_IF
  END_IF

  SELECT_CASE (Game.status)
  BEGIN_SELECT
    CASE -500 _TO_ -3:
      // The enemies are blocked by the clock
      INCR Game.status++;
      IF(Game.status == -2) THEN
        // Resumes the enemies
        Game.status = 0;
        IF(Game.time < 16) THEN
          //ChangePal 0
        ELSE
          //ChangePal -1
        END_IF
      END_IF
      END_CASE
    CASE -2:
      // Do the lightnings
      Game.status = 0;
      FOR(int i = 0 TO i < 80 STEP i++)
      BEGIN_FOR
        CALL DrawScreen();
      NEXT
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      //ChangePal -1
      END_CASE
    CASE -1:
      Game.status = 0;
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      END_CASE
    CASE_ELSE
      IF(Game.status > 0) THEN_DO INCR Game.status++;
  END_SELECT
« Last Edit: October 28, 2013, 05:16:48 PM by John »

Offline Charles Pegge

  • BASIC Developer
  • Posts: 69
Re: Wetspot II - C BASIC
« Reply #3 on: October 28, 2013, 02:48:54 PM »
Yes, that looks very good John. Normally I try to avoid uppercase commands in basic, but for translation to C, it certainly helps in avoiding symbol conflicts.

I'm working on dynamic strings, which is where C parts company with Basic big-time.

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #4 on: October 28, 2013, 05:01:41 PM »
Charles,

After I get the Wetspot II game converted to C BASIC, maybe I'll revive my SB2N project but this time convert BASIC code to C BASIC. Actually that should be a walk in the park for Daniel's uCalc Transform. (Kent, you got your ears on?)

Here is new version of the C BASIC Wetspot II game. I removed the QB45 code as it was beginning to serve no purpose. The C BASIC code should be readable by BASIC programmers and the C syntax that remains isn't that mysterious any longer. IMHO

Code: [Select]
// C BASIC

// NOTE: keywords without assignments are OPTIONAL
#define FUNCTION
#define BEGIN_FUNCTION {
#define END_FUNCTION }
#define SUB void
#define BEGIN_SUB {
#define END_SUB }
#define RETURN return
#define CALL
#define AND &&
#define OR ||
#define MOD %
#define DIM
#define AS
#define LET
#define INCR
#define IF if
#define BEGIN_IF {
#define THEN {
#define THEN_DO
#define ELSE } else {
#define END_IF }
#define FOR for
#define TO ;
#define STEP ;
#define BEGIN_FOR {
#define NEXT }
#define SELECT_CASE switch
#define BEGIN_SELECT {
#define CASE case
#define _TO_ ...
#define END_CASE break;
#define CASE_ELSE default:
#define END_SELECT }
#define DO do {
#define WHILE } while

// Wetspot II

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>

#include "wetspot2.h"
#include "font.h"
#include "palette.h"
#include "timer.h"
#include "logo.h"
#include "sprites.h"
#include "menu.h"
#include "world.h"
#include "input.h"
#include "sound.h"

DIM AS SDL_Surface *screen;
DIM AS SDL_Surface *gamescreen;
DIM AS SDL_Surface *theend;
DIM AS Uint8 *keys;
DIM AS GAMETYPE Game;
DIM AS PLAYERTYPE Player[2];
DIM AS ENEMYTYPE Enemy[MAXENEMIES];
DIM AS OBJECTTYPE Object[MAXOBJS];
DIM AS BLOCKTYPE Block[MAXBLOCKS];
DIM AS SHOTTYPE Shot[MAXSHOTS];
DIM AS DEATHTYPE Death[2];
DIM AS CELL cell[12][20];
DIM AS int Blocked;

SUB CheckScore(int PlayerNum)
BEGIN_SUB
  IF(Player[PlayerNum].score >= Player[PlayerNum].nextextra) THEN
    IF(Player[PlayerNum].nextextra == 30000) THEN_DO Player[PlayerNum].nextextra = 0;
    Player[PlayerNum].nextextra += 100000;
    INCR Player[PlayerNum].lives++;
    CALL PlaySound(7);
  END_IF
END_SUB

DIM AS int dx[5] = {0, -1, 0, 1, 0};
DIM AS int dy[5] = {1, 0, -1, 0, 0};

CALL int GetFreeObject();
CALL void KillEnemy(int);

SUB CheckStatus()
BEGIN_SUB
  IF(Game.players == 1) THEN
    IF(Player[0].dead == TRUE) THEN
      Game.status = 400;
      Player[0].dead = 2;
    END_IF
  ELSE
    IF(Player[0].dead == TRUE) THEN
      Player[0].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
    IF(Player[1].dead == TRUE) THEN
      Player[1].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
  END_IF
  IF(Game.objects < 3 AND Game.status != -501) THEN
    IF(Game.status < 1 AND Game.time > 15) THEN
      IF(rand() MOD 100 == 0) THEN
        LET int i = GetFreeObject();
        Object[i].x = rand() MOD 20;
        Object[i].y = rand() MOD 12;
        IF(cell[Object[i].y][Object[i].x].st == 0) THEN
          Object[i].typ = 26 + rand() MOD 8;
          Object[i].time = 0;
          IF(rand() MOD 2 == 0) THEN
            LET int xi = rand() MOD 20;
            LET int yi = rand() MOD 12;
            IF(cell[yi][xi].rd > 0) THEN_DO Object[i].typ = cell[yi][xi].rd;
            IF(Game.mode == DEMO AND Object[i].typ == 14) THEN_DO Object[i].typ = 0;
          END_IF
          IF(rand() MOD 3 == 0) THEN_DO Object[i].typ = rand() MOD 33 + 1;
          INCR Game.objects++;
        END_IF
      END_IF
    END_IF
  END_IF
  SELECT_CASE (Game.status)
  BEGIN_SELECT
    CASE -500 _TO_ -3:
      INCR Game.status++;
      IF(Game.status == -2) THEN
        Game.status = 0;
        IF(Game.time < 16) THEN
          // ChangePal 0
        ELSE
          // ChangePal -1
        END_IF
      END_IF
      END_CASE
    CASE -2:
      Game.status = 0;
      FOR(int i = 0 TO i < 80 STEP i++)
      BEGIN_FOR
        CALL DrawScreen();
      NEXT
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      // ChangePal -1
      END_CASE
    CASE -1:
      Game.status = 0;
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      END_CASE
    CASE_ELSE
      IF(Game.status > 0) THEN_DO INCR Game.status++;
  END_SELECT
  IF(Game.mode == DEMO) THEN_DO RETURN;
  IF(keys[SDLK_RETURN]) THEN
    keys[SDLK_RETURN] = 0;
    TimerOn = FALSE;
    CALL PlaySound(1);
    CALL DrawScreen();
    CALL SPrint("PAUSE!", 136, 96, Game.textcol);
    DO
      CALL BlitAndWait(2);
    WHILE(!keys[SDLK_RETURN]);
    keys[SDLK_RETURN] = 0;
    IF(Game.monsters > 0) THEN_DO TimerOn = TRUE;
  END_IF
END_SUB
« Last Edit: October 28, 2013, 08:58:12 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #5 on: October 28, 2013, 09:02:53 PM »
I cleaned up the C BASIC #define's and only include the keywords currently implemented. (see updated code in the previous post) Maybe Charles can post to his original thread a master #define list including what I have working and his work in progress.


Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #6 on: October 29, 2013, 03:23:39 PM »
I'm using in Wetspot II Charles's master #define keyword list that now includes my upper case / BASIC like version. If you C syntax that could be converted to #define to make the code more BASIC like, please let us know. If you're not a member, consider joining the All BASIC mailing list.

Code: [Select]
/*
    C BASIC

    NOTE: keywords without assignments are OPTIONAL
*/
#define function
#define method
#define gosub
#define dim
#define as
#define to
#define limit
#define step
#define then
#define procedure void
#define sub   void
#define begin {
#define end   }
#define and   &&
#define or    ||
#define class typedef struct
#define types typedef struct
#define methods
#define member ->
#define addressof &
#define has =
#define incr ++
#define decr --
#define next ++
#define prior --
#define byref *
#define ref   void*
#define references = &
#define FreeSpace free

#define FUNCTION
#define BEGIN_FUNCTION {
#define END_FUNCTION }
#define SUB void
#define BEGIN_SUB {
#define END_SUB }
#define RETURN return
#define CALL
#define AND &&
#define OR ||
#define MOD %
#define DIM
#define AS
#define LET
#define INCR ++
#define DECR --
#define IF if
#define BEGIN_IF {
#define THEN {
#define THEN_DO
#define ELSE } else {
#define END_IF }
#define FOR for
#define TO ;
#define STEP ;
#define BEGIN_FOR {
#define NEXT }
#define SELECT_CASE switch
#define BEGIN_SELECT {
#define CASE case
#define _TO_ ...
#define END_CASE break;
#define CASE_ELSE default:
#define END_SELECT }
#define DO do {
#define WHILE } while
 
/*
   Wetspot II
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>

#include "wetspot2.h"
#include "font.h"
#include "palette.h"
#include "timer.h"
#include "logo.h"
#include "sprites.h"
#include "menu.h"
#include "world.h"
#include "input.h"
#include "sound.h"

DIM AS SDL_Surface *screen;
DIM AS SDL_Surface *gamescreen;
DIM AS SDL_Surface *theend;
DIM AS Uint8 *keys;
DIM AS GAMETYPE Game;
DIM AS PLAYERTYPE Player[2];
DIM AS ENEMYTYPE Enemy[MAXENEMIES];
DIM AS OBJECTTYPE Object[MAXOBJS];
DIM AS BLOCKTYPE Block[MAXBLOCKS];
DIM AS SHOTTYPE Shot[MAXSHOTS];
DIM AS DEATHTYPE Death[2];
DIM AS CELL cell[12][20];
DIM AS int Blocked;

SUB CheckScore(int PlayerNum)
BEGIN_SUB
  IF(Player[PlayerNum].score >= Player[PlayerNum].nextextra) THEN
    IF(Player[PlayerNum].nextextra == 30000) THEN_DO Player[PlayerNum].nextextra = 0;
    Player[PlayerNum].nextextra += 100000;
    INCR Player[PlayerNum].lives;
    CALL PlaySound(7);
  END_IF
END_SUB

DIM AS int dx[5] = {0, -1, 0, 1, 0};
DIM AS int dy[5] = {1, 0, -1, 0, 0};

CALL int GetFreeObject();
CALL void KillEnemy(int);

SUB CheckStatus()
BEGIN_SUB
  IF(Game.players == 1) THEN
    IF(Player[0].dead == TRUE) THEN
      Game.status = 400;
      Player[0].dead = 2;
    END_IF
  ELSE
    IF(Player[0].dead == TRUE) THEN
      Player[0].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
    IF(Player[1].dead == TRUE) THEN
      Player[1].dead = 2;
      IF(Player[0].dead >= 2 AND Player[1].dead >= 2) THEN_DO Game.status = 400;
    END_IF
  END_IF
  IF(Game.objects < 3 AND Game.status != -501) THEN
    IF(Game.status < 1 AND Game.time > 15) THEN
      IF(rand() MOD 100 == 0) THEN
        LET int i = GetFreeObject();
        Object[i].x = rand() MOD 20;
        Object[i].y = rand() MOD 12;
        IF(cell[Object[i].y][Object[i].x].st == 0) THEN
          Object[i].typ = 26 + rand() MOD 8;
          Object[i].time = 0;
          IF(rand() MOD 2 == 0) THEN
            LET int xi = rand() MOD 20;
            LET int yi = rand() MOD 12;
            IF(cell[yi][xi].rd > 0) THEN_DO Object[i].typ = cell[yi][xi].rd;
            IF(Game.mode == DEMO AND Object[i].typ == 14) THEN_DO Object[i].typ = 0;
          END_IF
          IF(rand() MOD 3 == 0) THEN_DO Object[i].typ = rand() MOD 33 + 1;
          INCR Game.objects;
        END_IF
      END_IF
    END_IF
  END_IF
  SELECT_CASE (Game.status)
  BEGIN_SELECT
    CASE -500 _TO_ -3:
      INCR Game.status;
      IF(Game.status == -2) THEN
        Game.status = 0;
        IF(Game.time < 16) THEN
          /* ChangePal 0 */
        ELSE
          /* ChangePal -1 */
        END_IF
      END_IF
      END_CASE
    CASE -2:
      Game.status = 0;
      FOR(int i = 0 TO i < 80 STEP i++)
      BEGIN_FOR
        CALL DrawScreen();
      NEXT
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      /* ChangePal -1 */
      END_CASE
    CASE -1:
      Game.status = 0;
      FOR(int i = 0 TO i < MAXENEMIES STEP i++)
      BEGIN_FOR
        IF(Enemy[i].typ > 0) THEN_DO CALL KillEnemy(i);
      NEXT
      END_CASE
    CASE_ELSE
      IF(Game.status > 0) THEN_DO INCR Game.status;
  END_SELECT
  IF(Game.mode == DEMO) THEN_DO RETURN;
  IF(keys[SDLK_RETURN]) THEN
    keys[SDLK_RETURN] = 0;
    TimerOn = FALSE;
    CALL PlaySound(1);
    CALL DrawScreen();
    CALL SPrint("PAUSE!", 136, 96, Game.textcol);
    DO
      CALL BlitAndWait(2);
    WHILE(!keys[SDLK_RETURN]);
    keys[SDLK_RETURN] = 0;
    IF(Game.monsters > 0) THEN_DO TimerOn = TRUE;
  END_IF
END_SUB

CALL int Collide(int xPos, int yPos);

FUNCTION int GetFreeObject()
BEGIN_FUNCTION
  FOR(int i = 0 TO i < MAXOBJS STEP i++)
  BEGIN_FOR
    if(Object[i].typ == 0) return i;
  NEXT
  RETURN (MAXOBJS-1);
END_FUNCTION

/* Moves shots and check collisions */
SUB MoveShots()
BEGIN_SUB
  LET int Collision = -1;
  LET int mul = 0, expl = 0;

  FOR(int i = 0 TO i < MAXSHOTS STEP i++)
  BEGIN_FOR
    /* There's a shot moving */
    IF(Shot[i].typ > 0) THEN
      SELECT_CASE(Shot[i].typ)
      BEGIN_SELECT
      CASE 1:
      CASE 3:
        /* 1: Bubble
           2: Egg
           Moves the shot */
        Shot[i].x += Shot[i].ax;
        Shot[i].y += Shot[i].ay;
        IF(Shot[i].typ == 1) THEN
          mul = 2; expl = 4;
        ELSE
          mul = 4; expl = 5;
        END_IF
        /* If the shot hits a block, it's destroyed */
        IF(Shot[i].x MOD 16 == 0 AND Shot[i].y MOD 16 == 0) THEN
          IF(cell[(Shot[i].y + (Shot[i].ay * mul)) / 16][(Shot[i].x + (Shot[i].ax * mul)) / 16].st > 0) THEN
            IF(Shot[i].typ == 3) THEN_DO CALL PlaySound(12);
            Shot[i].typ = expl;
            Shot[i].time = 0;
          END_IF
        END_IF
        INCR Shot[i].time;
        IF(Shot[i].typ == 1) THEN
          Collision = Collide(Shot[i].x, Shot[i].y);
          IF(Collision != -1) THEN
            /* A player has been trapped by a bubble */
            IF(Player[Collision].status == 0) THEN
              Player[Collision].status = 120;
              Shot[i].typ = 0;
            END_IF
          END_IF
        ELSE
          Collision = Collide(Shot[i].x, Shot[i].y);
          IF(Collision != -1) THEN
            /* A player has been hit by an egg; he's killed */
            IF(Player[Collision].status == 0) THEN
              Player[Collision].status = 201;
              Player[Collision].dir = -8;
              Player[Collision].speed = 2;
              Player[Collision].dead = TRUE;
              Player[Collision].lives--;
              IF(Player[Collision].lives == -1) THEN_DO Player[Collision].levelreached = (Game.area * 5) + Game.level;
              Shot[i].typ = 0;
              PlaySound(16);
            END_IF
          END_IF
        END_IF
        END_CASE
      CASE 2:
        /* Green bouncing slime */
        Shot[i].x += Shot[i].ax;
        Shot[i].y += Shot[i].ay;
        IF(Shot[i].x MOD 16 == 0 AND Shot[i].y MOD 16 == 0) {
          /* If the shot hits a block, it bounces on it */
          IF(cell[(Shot[i].y + (Shot[i].ay * 4)) / 16][(Shot[i].x + (Shot[i].ax * 4)) / 16].st > 0) THEN
            Shot[i].ax = -Shot[i].ax;
            Shot[i].ay = -Shot[i].ay;
            CALL PlaySound(6);
          END_IF
        END_IF
        INCR Shot[i].time;
        /*  The shot can't move forever... */
        IF(Shot[i].time > 200) Shot[i].typ = 0;
        Collision = Collide(Shot[i].x, Shot[i].y);
        IF(Collision != -1) THEN
          IF(Player[Collision].status == 0) THEN
            /* A player has been hit by the shot; he's killed */
            Player[Collision].status = 201;
            Player[Collision].dir = -8;
            Player[Collision].speed = 2;
            Player[Collision].dead = TRUE;
            Player[Collision].lives--;
            IF(Player[Collision].lives == -1) THEN_DO Player[Collision].levelreached = (Game.area * 5) + Game.level;
            Shot[i].typ = 0;
            CALL PlaySound(16);
          END_IF
        END_IF
        END_CASE
      CASE 4:
      CASE 5:
        /* Each type of shot has its own explosion when it hits a block
           Only the green slime doesn't have an explosion! */
        INCR Shot[i].time;
        IF(Shot[i].time == 6) THEN_DO Shot[i].typ = 0;
      END_SELECT
    END_IF
  NEXT
END_SUB
« Last Edit: October 29, 2013, 08:54:09 PM by John »

kryton9

  • Guest
Link to Wetspot on the site
« Reply #7 on: October 29, 2013, 06:06:09 PM »
I just wanted to post this link to new users coming to the site and following this thread:
http://www.allbasic.info/forum/index.php?topic=258.msg2903#msg2903
« Last Edit: October 29, 2013, 06:58:41 PM by kryton9 »

kryton9

  • Guest
Re: Wetspot II - C BASIC
« Reply #8 on: October 29, 2013, 08:04:44 PM »
I am trying to put a code::blocks project together for this project. Anyways, just a reminder C does not support // for comments (mingw32) only /*  comment here */
http://msdn.microsoft.com/en-us/library/wfwda74e(v=vs.100).aspx

kryton9

  • Guest
Windows 32 bit Code::Blocks Project for WetSpot2
« Reply #9 on: October 29, 2013, 08:50:16 PM »
This is complete and has all that you need here.

I finally got a project made for Code::Blocks for WetSpot2. This is for Windows 32 bit.
I got rid of all the errors so far, except for a few warnings. (screenshot)
The code so far as posted on the forums is in main.c

I am also attaching a SDL 1.2.15 that I put together and converted the .libs to .a's for mingw32.
This has SDL, SDL_image, SDL_mixer, SDL_net and SDL_ttf.
The SDL 1.2.15 folder has a bin folder, these are the 32 bit dlls needed.
Add this to your PATH environment variable so you don't need to copy them all over the place.

Under Code::Blocks menubar: Settings::Compiler Click on the Search directories tab.
include folder which has all the includes and should be added to search directory under Compile
lib folder which has all of the libs, this should be added to search directory under Linker

I am using 7Zip for the compressions: http://www.7-zip.org/

Heads up: This makes an .exe file that will not do anything in Windows. It is just to test the code compilation.
« Last Edit: October 29, 2013, 09:16:14 PM by kryton9 »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #10 on: October 29, 2013, 09:18:31 PM »
Quote
Heads up: This makes an .exe file that will not do anything in Windows. It is just to test the code compilation.

I'm confused. Why doesn't it work if it compiles?


kryton9

  • Guest
Re: Wetspot II - C BASIC
« Reply #11 on: October 29, 2013, 10:07:46 PM »
John, I assumed it was because it was a MS-DOS game. I installed DOSBOX, knowing that my compile was 32 bit windows and probably wouldn't work.
It doesn't run in DOSBOX either as suspected.

I guess it compiles because the code is OK and all needed parts are there.  Probably need to compile in MS-DOS :)
Here is a screenshot to save others from having to test it out in DOSBOX.

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #12 on: October 29, 2013, 10:41:26 PM »
I wasn't aware that the game was converted to C to only run on Linux. AIR would be the best person to determine if that is the case. It would suck if this is a Linux only QB45 port.

As far as the DOS QB45 version I posted running on Android in a DOSBox goes, I used the pre-compiled version I attached. I couldn't get it to compile in the QB45 IDE on Android/DOSBox even with the suggested /L command line option. I even tried in dosemu which I feel is the best DOS emulator out there but it wouldn't run the pre-compiled QB45 DOS version which surprised me. I think the issue is minor as it's giving a disk write error.

I would also like to clarify my last point about using {} for single constructs. So far I have only run into one FOR statment that didn't use the bracketed encapsulation. I handle single line IF statements with no structure changes. (see optional THEN_DO) At this point I don't see this slowing me down if a random single construct FOR shows up.

« Last Edit: October 29, 2013, 11:00:02 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Wetspot II - Android
« Reply #13 on: October 30, 2013, 12:52:21 AM »
I'm please to announce that the Wetspot II C version compiled native on Android Linux with C4droid with all the bells and whistles. (touch background controls, on-screen keyboard, screen orientation, assign custom control buttons to keyboard keys and sound support) The wetsopt2.apk C4droid generated didn't seem to run. I will have to give it another try in the morning. I'm just happy it works on my development tablet.



onscreen controls disable


onscreen controls enabled


« Last Edit: October 30, 2013, 02:13:56 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 2875
    • ScriptBasic Open Source Project
Re: Wetspot II - C BASIC
« Reply #14 on: October 30, 2013, 11:47:27 AM »
The Android version of Wetspot II is by far the best running example yet. The on-screen touch controls work excellent and make game play a dream. Performance is outstanding and rivals any commercial arcade style game. The best part is I didn't have to make any code modifications to the C BASIC / gcc version to get it working on Android. That in itself should be motivation to contribute to the C BASIC project.
 
« Last Edit: October 30, 2013, 02:04:42 PM by John »