Dive in and Create
eC comes bundled with the Ecere SDK, providing a comprehensive API for building apps ranging from games to business, for desktop, mobile and web platforms.
eC comes bundled with the Ecere SDK, providing a comprehensive API for building apps ranging from games to business, for desktop, mobile and web platforms.
class HelloApp : Application
{
void Main()
{
PrintLn("Hello, World!!");
}
}
import "ecere"
class HelloForm : Window
{
text = "My First eC Application";
borderStyle = sizable;
clientSize = { 304, 162 };
hasClose = true;
Label label
{
this, position = { 10, 10 }, font = { "Arial", 30 },
text = "Hello, World!!"
};
};
HelloForm hello { };
import "ecere"
class MyApp : GuiApplication
{
driver = "OpenGL";
};
Camera camera
{
fixed,
position = Vector3D { 0, 0, -350 },
orientation = Euler { 0, 0, 0 },
fov = 53;
};
Light light
{
diffuse = lightCoral;
orientation = Euler { pitch = 10, yaw = 30 };
};
class Hello3D : Window
{
text = "Hello, 3D";
background = black;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
clientSize = { 304, 162 };
Cube cube { };
bool OnLoadGraphics()
{
cube.Create(displaySystem);
cube.transform.scaling = { 100, 100, 100 };
cube.transform.orientation = Euler { 50, 30, 50 };
cube.UpdateTransform();
return true;
}
void OnResize(int w, int h)
{
camera.Setup(w, h, null);
camera.Update();
}
void OnRedraw(Surface surface)
{
surface.Clear(depthBuffer);
display.SetLight(0, light);
display.SetCamera(surface, camera);
display.DrawObject(cube);
display.SetCamera(surface, null);
}
}
Hello3D hello3D {};
import "ecere"
import "gnosis"
import "view3Dcontroller"
class MyScene : Scene
{
gis::Map { source = { "/Maps/BlueMarbleNextGen" } };
}
MyScene scene { };
class MainWindow : Window
{
displayDriver = "OpenGL";
caption = "GnosIS Sample";
background = black;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
size = { 640, 480 };
View3D view { scene = scene };
controller = View3DController
{
this, controlled = view,
position = { 24.01064, -96.86049, Kilometers { 8000 } };
orientation = { yaw = 10, pitch = 80, roll = -10 };
};
}
import "ecere"
class MyApp : GuiApplication
{
driver = "OpenGL";
// driver = "Direct3D";
};
Camera camera
{
fixed,
position = Vector3D { 0, 0, -300 },
orientation = Euler { 0, 0, 0 },
fov = 70;
};
Light light
{
//diffuse = white;
specular = white;
orientation = Euler { pitch = 10, yaw = 30 };
};
Light light2
{
diffuse = white;
//specular = white;
orientation = Euler { pitch = 20, yaw = -30 };
};
class Test3D : Window
{
text = "Form1";
background = black;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
clientSize = { 304, 162 };
BitmapResource texture { "http://www.ecere.com/images/knot.png", window = this };
Sphere sphere { };
Cube cube { };
Material sphereMat { diffuse = white, ambient = blue, specular = red, power = 8 };
Material cubeMat { opacity = 1.0f, diffuse = white, ambient = white, flags = { doubleSided = true, translucent = true } };
bool OnLoadGraphics()
{
sphere.Create(displaySystem);
sphere.mesh.ApplyMaterial(sphereMat);
sphere.transform.scaling = { 75, 75, 75 };
sphere.transform.position = { 100, 0, 0 };
sphere.UpdateTransform();
cubeMat.baseMap = texture.bitmap;
cube.Create(displaySystem);
cube.mesh.ApplyMaterial(cubeMat);
cube.mesh.ApplyTranslucency(cube);
cube.transform.scaling = { 100, 100, 100 };
cube.transform.position = { -100, 0, 0 };
cube.transform.orientation = Euler { 50, 50 };
cube.UpdateTransform();
return true;
}
void OnResize(int w, int h)
{
camera.Setup(w, h, null);
}
void OnRedraw(Surface surface)
{
surface.Clear(depthBuffer);
camera.Update();
display.SetLight(0, light);
display.SetLight(1, light2);
display.fogDensity = 0;
display.SetCamera(surface, camera);
display.DrawObject(cube);
display.DrawObject(sphere);
display.SetCamera(surface, null);
}
}
Test3D test3D {};
#include <GL/gl.h>
import "ecere"
#define GL_MULTISAMPLE_ARB 0x809D
class GLTriangle : Window
{
text = "Triangle";
displayDriver = "OpenGL";
background = activeBorder;
nativeDecorations = true;
borderStyle = sizable;
hasMaximize = true, hasMinimize = true, hasClose = true;
clientSize = { 304, 162 };
void OnRedraw(Surface surface)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-30, 30, -30, 30, -30, 30);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-15, -15, 0);
glShadeModel(GL_SMOOTH);
glEnable(GL_MULTISAMPLE_ARB);
glBegin(GL_TRIANGLES);
glColor3f(1, 0, 0); glVertex2f(0, 0);
glColor3f(0, 1, 0); glVertex2f(30, 0);
glColor3f(0, 0, 1); glVertex2f(0, 30);
glEnd();
}
}
GLTriangle window {};
import "EDA"
import "genericEditor"
enum MediaType { unknown, tape, dvd, bluRay };
dbtable "Borrowers" Borrower
{
Borrower id "ID";
String name "Name";
String phoneNumber "Phone Number";
};
dbtable "Movies" Movie
{
Movie id "ID";
String name "Name";
MediaType mediaType "Media Type";
Date dateAdded "Date Added";
Borrower borrower "Borrower";
Date dateBorrowed "Date Borrowed";
};
DataSource ds;
Database db;
class MovieCollectionApp : GuiApplication
{
MovieCollectionApp()
{
SetDefaultIdField("ID");
SetDefaultNameField("Name");
ds = DataSource { driver = "SQLite" };
//ds = DataSource { driver = "Oracle", host = "localhost", port = "1521", user = "test", pass = "test" };
db = database_open(ds, "collection");
}
~MovieCollectionApp()
{
delete db;
delete ds;
}
}
class MovieCollectionForm : Window
{
text = "Movie Collection";
background = activeBorder;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
hasMenuBar = true;
size = { 576, 432 };
Menu fileMenu { menu, "File", f };
MenuItem exit { fileMenu, "Exit", x, altF4, NotifySelect = MenuFileExit };
Menu reportsMenu { menu, "Reports", r };
GenericEditor editor { this, anchor = { 0, 0, 0, 0 }, table = dbtable("Movies"),
list.text = "List of Movies", editor.text = "Movie Entry Being Edited" };
Button editBorrowers
{
this, caption = "Edit Borrowers", altB, stayOnTop = true, anchor = { right = 40, bottom = 40 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
GenericEditor borrowersEditor
{
hasClose = true;
borderStyle = sizable;
size = { 640, 300 };
table = dbtable("Borrowers");
list.text = "List of Borrowers", editor.text = "Borrower Entry Being Edited";
};
borrowersEditor.Modal();
editor.dataBoxes[3].Refresh();
return true;
}
};
}
MovieCollectionForm mainForm {};
import "ecere"
// We'll use TCP/IP port 5623 for this sample
define samplePort = 5623;
// We will use this simple structure for our messages
struct SamplePacket
{
int stringLen;
// stringLen + 1 bytes are actually used (variable size depending on string)
char string[1];
};
class SampleService : Service
{
void OnAccept()
{
// When we get an incoming connection to our service, we spawn a SampleSocket (Can only serve one right now)
if(!servingSocket)
{
servingSocket = SampleSocket { this };
form.UpdateButtonStates();
}
}
}
class SampleSocket : Socket
{
void OnConnect()
{
// We want a non blocking Connect() call, so we define an OnConnect() that simply updates the button disabled states
form.UpdateButtonStates();
}
void OnDisconnect(int code)
{
// On disconnection we need to null the socket pointers, and update the buttons
if(connectedSocket == this)
connectedSocket = null;
else if(servingSocket == this)
servingSocket = null;
form.UpdateButtonStates();
}
unsigned int OnReceive(unsigned char * buffer, unsigned int count)
{
// We only process the data if we've received enough bytes to make up the message
// This first if just checks if we have reveived enough bytes for the header
if(count >= sizeof(SamplePacket))
{
SamplePacket * packet = (SamplePacket *) buffer;
uint size = sizeof(SamplePacket) + packet->stringLen;
// Here we check if we've actually received the entire message
if(count >= size)
{
// We've received a complete message, so we change the contents of the recvString EditBox
form.recvString.contents = packet->string;
// and we return the size of the message we've processed.
// If more data is already buffered, this method will be called again right away.
return size;
}
}
// We haven't received enough data to process this message yet: return 0 bytes processed
// This method will be called again once more data has been received.
return 0;
}
}
class SocketSample : Window
{
text = "Socket Sample";
background = activeBorder;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
tabCycle = true;
size = { 416, 176 };
nativeDecorations = true;
// Service is missing a property to tell us if it's listening or not already, so we keep track of it in this variable
bool listening;
void UpdateButtonStates()
{
bool connected = (connectedSocket && connectedSocket.connected) || (servingSocket && servingSocket.connected);
// The Send button is disabled if we're not connected
btnSend.disabled = !connected;
// The Connect button is disabled if we've already defined a connectedSocket
btnConnect.disabled = connectedSocket != null;
// The Listen button is disabled if we're already listening
btnListen.disabled = listening;
}
Button btnSend
{
this, text = "Send", position = { 344, 64 }, disabled = true;
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
// We build up a SamplePacket here with our message from the sentString EditBox
String string = sentString.contents;
int len = strlen(string);
int size = sizeof(SamplePacket) + len;
SamplePacket * packet = (SamplePacket *)new byte[size];
packet->stringLen = len;
memcpy(packet->string, string, len+1);
// If we've connected to another server, we use the connectedSocket, otherwise we use the servingSocket (Send back to whom connected to us)
(connectedSocket ? connectedSocket : servingSocket).Send(packet, size);
// Make sure to free memory allocated with 'new'
delete packet;
return true;
}
};
EditBox serverAddress { this, text = "Server Address", size = { 174, 19 }, position = { 8, 40 }, contents = "localhost" };
Label lblServerAddress { this, position = { 8, 16 }, labeledWindow = serverAddress };
Button btnListen
{
this, text = "Listen", position = { 144, 104 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
// Start listening here
if(service.Start())
{
listening = true;
UpdateButtonStates();
}
return true;
}
};
EditBox sentString { this, text = "Sent String", size = { 166, 19 }, position = { 224, 40 } };
Label lblSentString { this, position = { 224, 16 }, labeledWindow = sentString };
EditBox recvString { this, text = "Received String", size = { 166, 19 }, position = { 224, 104 } };
Label label1 { this, position = { 224, 80 }, labeledWindow = recvString };
Button btnConnect
{
this, text = "Connect", position = { 8, 72 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
btnConnect.disabled = true;
// Create a socket and attempt a connection to the address specified in the serverAddress EditBox
connectedSocket = SampleSocket { };
// Connect is a blocking call if no OnConnect method is defined in the Socket, a non-blocking call otherwise
connectedSocket.Connect(serverAddress.contents, samplePort);
return true;
}
};
void OnDestroy()
{
// We need to disconnect the socket and stop the service before destroying the application,
// otherwise we'll get a crash with the SampleSocket accessing the form that is already destroyed
if(connectedSocket)
connectedSocket.Disconnect(0);
service.Stop();
}
}
// The form
SocketSample form {};
// The service
SampleService service { port = samplePort };
// We use 2 sockets: one for when we connect to a server, one for the incoming connections to our SampleService
SampleSocket connectedSocket, servingSocket;
// -- main.ec -----------------------
import "ecere"
import remote "Server"
ChatConnection connection;
class Form1 : Window
{
caption = $"Server";
background = formColor;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
clientSize = { 640, 460 };
EditBox log { this, anchor = { left = 16, top = 56, right = 26, bottom = 81 }, multiLine = true };
EditBox serverAddress { this, size = { 182, 27 }, anchor = { top = 16, right = 98 }, contents = "localhost" };
Button btnConnect
{
this, caption = $"Connect", anchor = { top = 24, right = 28 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
connection = ChatConnection
{
void NotifyMessage(const String msg)
{
form1.log.PutS(" < ");
form1.log.PutS(msg);
form1.log.PutS("\n");
}
void OnDisconnect(int code)
{
DCOMClientObject::OnDisconnect(code);
if(form1)
form1.btnSend.disabled = true;
}
};
if(connection.Connect(serverAddress.contents, 1494))
{
connection.Join();
btnSend.disabled = false;
}
return true;
}
};
Button btnHost
{
this, text = "Host", position = { 32, 16 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
chatService.Start();
return true;
}
};
EditBox message { this, size = { 510, 43 }, anchor = { left = 16, right = 114, bottom = 17 } };
Button btnSend
{
this, caption = $"Send", isDefault = true, size = { 60, 37 }, anchor = { right = 28, bottom = 23 }, disabled = true;
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
if(serverConnection)
SendBackMessage(message.contents);
else
connection.SendMessage(message.contents);
log.PutS(" > ");
log.PutS(message.contents);
log.PutS("\n");
message.Clear();
return true;
}
};
}
Form1 form1 {};
DCOMService chatService { port = 1494 };
// -- Server.ec -----------------------
import "main"
ChatConnection serverConnection;
public remote class ChatConnection
{
public:
~ChatConnection()
{
if(serverConnection == this && form1)
form1.btnSend.disabled = false;
}
void Join()
{
serverConnection = this;
form1.btnSend.disabled = false;
}
void SendMessage(const String msg)
{
form1.log.PutS(" < ");
form1.log.PutS(msg);
form1.log.PutS("\n");
}
virtual void NotifyMessage(const String msg);
private:
}
void SendBackMessage(const String msg)
{
serverConnection.NotifyMessage(msg);
}
import "ecere"
static char * indexNames[] =
{
"index.html",
"index.htm",
"home.html",
"home.htm",
"welcome.html",
"welcome.htm",
"default.html",
"default.htm"
};
#define NUM_INDEX (sizeof(indexNames) / sizeof(char *))
static void WriteFileName(File f, char * fileName)
{
byte ch;
int c;
for(c = 0; (ch = fileName[c]); c++)
{
if(ch <= 32 || ch > 128)
{
byte nibble;
f.Putc('%');
nibble = (ch & 0xF0) >> 4;
f.Putc((nibble > 9) ? (nibble - 10 + 'a') : (nibble + '0'));
nibble = ch & 0x0F;
f.Putc((nibble > 9) ? (nibble - 10 + 'a') : (nibble + '0'));
}
else
f.Putc(ch);
}
}
#define CONTENT_PATH "."
static void CreateDirectoryListing(File f, char * directory)
{
FileListing listing { directory };
f.Puts("<HTML><HEAD></HEAD><BODY>\r\n");
if(directory[0] && directory[1] && (directory[1] != ':' || (directory[2] && directory[3])))
f.Puts("<A HREF=../>../</A><BR>\r\n");
while(listing.Find())
{
f.Puts("<A HREF=");
WriteFileName(f, listing.name);
if(listing.stats.attribs.isDirectory)
f.Puts("/");
f.Puts(">");
f.Puts(listing.name);
f.Puts("</A><BR>\r\n");
}
f.Puts("\r\n</BODY></HTML>\r\n");
}
static char * GetString(char * string, char * what, int count)
{
int c;
bool result = true;
for(c = 0; what[c]; c++)
{
if((count && c >= count) || (string[c] != what[c] && tolower(string[c]) != tolower(what[c])))
return null;
}
return string + c;
}
class HTTPClient : Socket
{
File f;
bool close;
#define ishexdigit(x) (isdigit(x) || (x >= 'a' && x<='f') || (x >= 'A' && x <= 'F'))
uint OnReceive(const byte * buffer, uint count)
{
int c;
for(c = 0; c<count-1; c++)
{
if(buffer[c] == '\r' && buffer[c+1] == '\n')
break;
}
if(c<count)
{
char * string = (char *)buffer;
if((string = GetString((char *)buffer, "GET ", count)))
{
char reply[1024];
char path[MAX_LOCATION];
char addedPath[MAX_LOCATION];
int d, i;
FileAttribs attribs;
int len = 0;
strcpy(path, CONTENT_PATH);
for(d = c; d > 0 && string[d] != ' '; d--);
for(i = 0; i<d; i++)
{
if(string[i] == '%' && ishexdigit(string[i+1]) && ishexdigit(string[i+2]))
{
char digits[3];
digits[0] = string[i+1];
digits[1] = string[i+2];
digits[2] = '\0';
addedPath[len++] = (byte)strtol(digits, null, 16);
i += 2;
}
else
addedPath[len++] = string[i];
addedPath[len] = '\0';
}
PathCat(path, addedPath+1);
attribs = FileExists(path);
if(attribs.isDirectory)
{
if(addedPath[len-1] != '/')
{
strcpy(reply, "HTTP/1.1 301 Moved Permantently\r\n");
strcat(reply, "Location: ");
strcat(reply, addedPath);
strcat(reply, "/\r\n");
strcat(reply, "Content-Length: 0\r\n\r\n");
}
else
{
int i;
char indexFile[MAX_LOCATION];
for(i = 0; i<NUM_INDEX; i++)
{
strcpy(indexFile, path);
PathCat(indexFile, indexNames[i]);
if(FileExists(indexFile).isFile)
{
f = FileOpen(indexFile, read);
break;
}
}
// List contents if we didn't find an index
if(i == NUM_INDEX)
{
f = TempFile {};
if(f)
{
CreateDirectoryListing(f, path);
f.Seek(0, start);
}
}
}
}
else if(attribs.isFile)
f = FileOpen(path, read);
else
strcpy(reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
if(f)
{
char extension[MAX_EXTENSION];
uint size = f.GetSize();
sprintf(reply, "HTTP/1.1 200 OK\r\n");
GetExtension(addedPath, extension);
if(attribs.isDirectory || !strcmp(extension, "html") || !strcmp(extension, "htm"))
strcat(reply, "Content-Type: text/html\r\n");
else
strcat(reply, "Content-Type: text/plain\r\n");
sprintf(strchr(reply, 0), "Content-Length: %d\r\n\r\n", size);
}
SendString(reply);
}
return c+2;
}
return count;
}
}
class HTTPServer : Service
{
void OnAccept()
{
HTTPClient { this };
}
}
class HTTPApplication : GuiApplication
{
bool Init()
{
httpServer.Start();
return true;
}
bool Cycle(bool idle)
{
bool result = true;
HTTPClient client, next;
for(client = (HTTPClient)httpServer.firstClient; client; client = next)
{
next = (HTTPClient)client.next;
if(client.f)
{
#define PACKETSIZE 65536
static byte buffer[PACKETSIZE];
int read = client.f.Read(buffer, 1, PACKETSIZE);
if(read)
client.Send(buffer, read);
if(client.f.Eof())
{
delete client.f;
if(client.close)
client.Disconnect(0);
}
result = true;
}
}
return result;
}
}
HTTPServer httpServer { port = 8080 };
Window serverWindow { size = Size { 320, 200 }, text = "ECERE HTTP Server", hasMinimize = true, hasClose = true };
import "ecere"
define spacing = 20;
define lineWidth = 10;
define mastery = 97;
define noAvailableMove = -100;
enum TTTSquare { _, X, O };
TTTSquare board[3][3];
class TicTacToe : Window
{
caption = "TicTacToe";
background = white;
hasClose = true;
clientSize = { 400, 400 };
FontResource tttFont { "Comic Sans MS", 50, bold = true, window = this };
TTTSquare turn; turn = X;
TicTacToe()
{
RandomSeed((uint)(GetTime() * 1000));
}
TTTSquare FindTicTacToe(TTTSquare state[3][3])
{
int i;
// Diagonal '\'
if(state[0][0] && state[0][0] == state[1][1] && state[1][1] == state[2][2])
return state[0][0];
// Diagonal '/'
if(state[2][0] && state[2][0] == state[1][1] && state[1][1] == state[0][2])
return state[2][0];
for(i = 0; i < 3; i++)
{
// Horizontal
if(state[i][0] && state[i][0] == state[i][1] && state[i][1] == state[i][2])
return state[i][0];
// Vertical
if(state[0][i] && state[0][i] == state[1][i] && state[1][i] == state[2][i])
return state[0][i];
}
return 0;
}
float BestMove(TTTSquare t, TTTSquare state[3][3], Point bestMove)
{
static int level = 0;
int x, y;
float bestRating = noAvailableMove;
int filled = 0;
bool couldTicTacToe = false;
Point badMove; /* A player is likely to see the opponent's tic tac toe in his own tic tac toe spot */
Point moves[9];
int numMoves = 0;
level++;
for(y = 0; y < 3; y++)
for(x = 0; x < 3; x++)
if(state[y][x]) filled++;
for(y = 0; y < 3; y++)
{
for(x = 0; x < 3; x++)
{
if(!state[y][x])
{
float newRating;
state[y][x] = t;
if(FindTicTacToe(state))
newRating = 1;
else
{
Point move;
newRating = BestMove((t == X) ? O : X, state, move);
if(newRating == noAvailableMove)
newRating = 0;
newRating = -newRating/2;
if(newRating <= -0.25f)
{
badMove = move;
couldTicTacToe = true;
}
}
state[y][x] = 0;
if(newRating > bestRating)
{
bestRating = newRating;
bestMove = { x, y };
numMoves = 1;
moves[0] = bestMove;
}
else if(level == 1 && newRating == bestRating)
moves[numMoves++] = { x, y };
}
}
}
if(GetRandom(0, 60) > mastery || (filled > 4 && filled < 7 && couldTicTacToe && (bestMove.x != badMove.x || bestMove.y != badMove.y)))
{
if(level == 2 && GetRandom(0, 25) > mastery)
bestRating = -0.5f;
if(level == 4 && GetRandom(0, 100) > mastery)
bestRating = -0.125f;
}
if(level == 1 && numMoves > 1)
bestMove = moves[GetRandom(0, numMoves-1)];
level--;
return bestRating;
}
void MovePlayed()
{
TTTSquare result = FindTicTacToe(board);
if(result)
{
MessageBox { caption = "Tic Tac Toe!", contents = (result == X ? "You win!" : "Computer wins!") }.Modal();
turn = 0;
}
else if(turn == X)
{
// Computer plays
Point move { };
turn = O;
if(BestMove(turn, board, move) != noAvailableMove)
{
board[move.y][move.x] = O;
MovePlayed();
}
else
turn = 0;
}
else
turn = X;
}
void DrawPieces(Surface surface)
{
int sw = (clientSize.w - 2*spacing) / 3;
int sh = (clientSize.h - 2*spacing) / 3;
int x, y;
int Xw, Xh, Ow, Oh;
surface.font = tttFont.font;
surface.TextExtent("X", 1, &Xw, &Xh);
surface.TextExtent("O", 1, &Ow, &Oh);
for(y = 0; y < 3; y++)
{
for(x = 0; x < 3; x++)
{
TTTSquare p = board[y][x];
if(p == X)
{
surface.foreground = green;
surface.WriteText(spacing + sw * x + sw / 2 - Xw/2, spacing + sh * y + sh / 2 - Xh/2, "X", 1);
}
else if(p == O)
{
surface.foreground = red;
surface.WriteText(spacing + sw * x + sw / 2 - Ow/2, spacing + sh * y + sh / 2 - Oh/2, "O", 1);
}
}
}
}
void OnRedraw(Surface surface)
{
int sw = (clientSize.w - 2*spacing) / 3;
int sh = (clientSize.h - 2*spacing) / 3;
surface.background = blue;
// Vertical lines
surface.Area(spacing + sw - lineWidth / 2, spacing, spacing + sw + lineWidth / 2-1, clientSize.h - spacing - 1);
surface.Area(spacing + sw*2 - lineWidth / 2, spacing, spacing + sw*2 + lineWidth / 2-1, clientSize.h - spacing - 1);
// Horizontal lines
surface.Area(spacing, spacing + sh - lineWidth / 2, clientSize.w - spacing - 1, spacing + sh + lineWidth / 2-1);
surface.Area(spacing, spacing + sh*2 - lineWidth / 2, clientSize.w - spacing - 1, spacing + sh*2 + lineWidth / 2-1);
DrawPieces(surface);
}
bool OnLeftButtonDown(int mx, int my, Modifiers mods)
{
if(turn == X && mx >= spacing && mx < clientSize.w - spacing && my >= spacing && my < clientSize.h - spacing)
{
int sw = (clientSize.w - 2*spacing) / 3;
int sh = (clientSize.h - 2*spacing) / 3;
mx -= spacing;
my -= spacing;
if((mx < sw - lineWidth / 2 || mx > sw + lineWidth / 2) && /* 1st vertical line */
(mx < sw*2 - lineWidth / 2 || mx > sw*2 + lineWidth / 2) && /* 2nd vertical line */
(my < sh - lineWidth / 2 || my > sh + lineWidth / 2) && /* 1st horizontal line */
(my < sh*2 - lineWidth / 2 || my > sh*2 + lineWidth / 2)) /* 2nd horizontal line */
{
int x = mx / sw;
int y = my / sh;
if(!board[y][x])
{
board[y][x] = X;
Update(null);
MovePlayed();
}
}
}
return true;
}
Button btnReset
{
this, font = { "Arial", 12 }, caption = "Reset", position = { 8, 8 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
memset(board, 0, sizeof(board));
turn = X;
Update(null);
return true;
}
};
}
TicTacToe mainForm {};
import "EcereAudio"
// There are 12 half-tones in an octave, and the frequency doubles in an octave.
define Do = 1.0;
define Do_ = 1.0594630943592952645618252949463; // The root 12 of 2.
define Re = Do_*Do_;
define Re_ = Re*Do_;
define Mi = Re_*Do_;
define Fa = Mi*Do_;
define Fa_ = Fa*Do_;
define Sol = Fa_*Do_;
define Sol_ = Sol*Do_;
define La = Sol_*Do_;
define La_ = La*Do_;
define Si = La_*Do_;
class MainWindow : Window
{
text = "A keyboard piano";
background = black;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
size = { 576, 432 };
Mixer mixer { };
Sound piano { "piano.wav" };
Sound xylophone { "xylophone.wav" };
Sound cello { "cello.wav" };
Sound tone { "tone.wav" };
Sound instrument;
Voice lastVoice;
instrument = piano;
bool OnCreate()
{
mixer.systemHandle = systemHandle;
return true;
}
void OnDestroy()
{
delete mixer;
}
bool OnKeyDown(Key key, unichar ch)
{
if(instrument == cello && lastVoice)
lastVoice.volume = 0;
switch(key)
{
case f1: instrument = piano; break;
case f2: instrument = xylophone; break;
case f3: instrument = cello; break;
case f4: instrument = tone; break;
// The regular octave on the zxcvbn row, sharps above (asdf)
case z: lastVoice = mixer.Play(instrument, 1.0, -1, Do); break;
case x: lastVoice = mixer.Play(instrument, 1.0, -.8, Re); break;
case c: lastVoice = mixer.Play(instrument, 1.0, -.6, Mi); break;
case v: lastVoice = mixer.Play(instrument, 1.0, -.4, Fa); break;
case b: lastVoice = mixer.Play(instrument, 1.0, -.2, Sol); break;
case n: lastVoice = mixer.Play(instrument, 1.0, 0, La); break;
case m: lastVoice = mixer.Play(instrument, 1.0, .2, Si); break;
case comma: lastVoice = mixer.Play(instrument, 1.0, .4, Do*2); break;
case period:lastVoice = mixer.Play(instrument, 1.0, .6, Re*2); break;
case slash: lastVoice = mixer.Play(instrument, 1.0, .8, Mi*2); break;
case s: lastVoice = mixer.Play(instrument, 1.0, -.9, Do_); break;
case d: lastVoice = mixer.Play(instrument, 1.0, -.7, Re_); break;
case g: lastVoice = mixer.Play(instrument, 1.0, -.3, Fa_); break;
case h: lastVoice = mixer.Play(instrument, 1.0, -.1, Sol_); break;
case j: lastVoice = mixer.Play(instrument, 1.0, .1, La_); break;
case l: lastVoice = mixer.Play(instrument, 1.0, .5, Do_*2); break;
case colon: lastVoice = mixer.Play(instrument, 1.0, .7, Re_*2); break;
// The lower octave on the qwerty row, sharps above (digits)
case q: lastVoice = mixer.Play(instrument, 1.0, 0, Do/2); break;
case w: lastVoice = mixer.Play(instrument, 1.0, 0, Re/2); break;
case e: lastVoice = mixer.Play(instrument, 1.0, 0, Mi/2); break;
case r: lastVoice = mixer.Play(instrument, 1.0, 0, Fa/2); break;
case t: lastVoice = mixer.Play(instrument, 1.0, 0, Sol/2); break;
case y: lastVoice = mixer.Play(instrument, 1.0, 0, La/2); break;
case u: lastVoice = mixer.Play(instrument, 1.0, 0, Si/2); break;
case i: lastVoice = mixer.Play(instrument, 1.0, 0, Do); break;
case o: lastVoice = mixer.Play(instrument, 1.0, 0, Re); break;
case p: lastVoice = mixer.Play(instrument, 1.0, 0, Mi); break;
case k2: lastVoice = mixer.Play(instrument, 1.0, 0, Do_/2); break;
case k3: lastVoice = mixer.Play(instrument, 1.0, 0, Re_/2); break;
case k5: lastVoice = mixer.Play(instrument, 1.0, 0, Fa_/2); break;
case k6: lastVoice = mixer.Play(instrument, 1.0, 0, Sol_/2); break;
case k7: lastVoice = mixer.Play(instrument, 1.0, 0, La_/2); break;
case k9: lastVoice = mixer.Play(instrument, 1.0, 0, Do_); break;
case k0: lastVoice = mixer.Play(instrument, 1.0, 0, Re_); break;
}
return true;
}
}
MainWindow mainWindow { };
import "ecere"
class Form1 : Window
{
background = 0;
opacity = 0;
font = { "Arial", 40 };
size = { 220, 60 };
#if defined(__linux__) // Alpha blended windows only work in OpenGL on Linux at the moment
displayDriver = "OpenGL";
#endif
alphaBlend = true;
moveable = true;
stayOnTop = true;
showInTaskBar = false;
Timer timer
{
userData = this, started = true, delay = 0.2;
bool DelayExpired()
{
Update(null);
return true;
}
};
bool OnLeftButtonDown(int x, int y, Modifiers mods)
{
MenuWindowMove(null, mods);
return true;
}
bool OnKeyDown(Key key, unichar ch)
{
if(key == escape) Destroy(0);
return true;
}
void OnRedraw(Surface surface)
{
DateTime time;
surface.Clear(colorBuffer);
time.GetLocalTime();
surface.SetForeground({ 128, darkGray });
surface.WriteTextf(0,0, "%02d:%02d:%02d",
time.hour, time.minute, time.second);
surface.SetForeground({ 192, teal });
surface.WriteTextf(2, 2, "%02d:%02d:%02d",
time.hour, time.minute, time.second);
}
}
Form1 form1 { };
import "HTMLView"
//define homeLocation = "localhost:8080";
//define homeLocation = "www.ecere.com";
define homeLocation = "google.com";
class AddressBar : Window
{
background = activeBorder;
tabCycle = true;
Button back
{
this, bevelOver = true, inactive = true, anchor = Anchor { left = 0, top = 0, bottom = 0 }, size = Size { 24 }, hotKey = altLeft, bitmap = { "<:ecere>actions/goPrevious.png" };
disabled = true;
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
((Explorer)parent).Back();
return true;
}
};
Button forward
{
this, bevelOver = true, inactive = true, anchor = Anchor { left = 24, top = 0, bottom = 0 }, size = Size { 24 }, hotKey = altRight, bitmap = { "<:ecere>actions/goNext.png" };
disabled = true;
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
((Explorer)parent).Forward();
return true;
}
};
Button home
{
this, bevelOver = true, inactive = true, anchor = Anchor { left = 52, top = 0, bottom = 0 }, size = Size { 24 }, hotKey = ctrlH, bitmap = { "<:ecere>actions/goHome.png" };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
((Explorer)parent).Go(homeLocation);
return true;
}
};
Button refresh
{
this, bevelOver = true, inactive = true, anchor = Anchor { left = 76, top = 0, bottom = 0 }, size = Size { 24 }, hotKey = f5, bitmap = { "<:ecere>actions/viewRefresh.png" };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
((Explorer)parent).Refresh();
return true;
}
};
Label { this, anchor = Anchor { left = (96+12) }, labeledWindow = address };
EditBox address
{
this, text = "Address:", anchor = Anchor { left = (16+48+96), right = 60, top = 0, bottom = 0 }, hotKey = altD;
bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
{
if(!go.disabled && (SmartKey)key == enter)
((Explorer)parent).Go(editBox.contents);
return true;
}
void NotifyUpdate(EditBox editBox)
{
String location = ((Explorer)parent).htmlView.location;
go.disabled = !strcmp(location ? location : "", editBox.contents);
}
};
Button go
{
this, bevelOver = true, inactive = true, text = "Go!", anchor = Anchor { top = 0, right = 0, bottom = 0 }, size = Size { 60 }, hotKey = altG;
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
((Explorer)parent).Go(address.contents);
return true;
}
};
bool OnKeyHit(Key key, unichar ch)
{
if(key == escape)
((Explorer)parent).htmlView.MakeActive();
return true;
}
}
class Explorer : Window
{
FileDialog openFileDialog { caption = "Select a file or enter a URL... " };
FileDialog saveFileDialog { type = save, caption = "Save to file... " };
icon = { ":newb.png" };
tabCycle = true;
background = activeBorder;
hasMenuBar = true;
hasStatusBar = true;
borderStyle = sizable;
hasClose = true;
hasMaximize = true;
hasMinimize = true;
text = "Ecere Web Browser";
size = Size { 800, 600 };
state = maximized;
AddressBar addressBar { this, borderStyle = bevel, anchor = Anchor { top = 0, left = 0, right = 0 }, size.h = 26, hotKey = altD };
HTMLView htmlView { this, borderStyle = deep, hasVertScroll = true, hasHorzScroll = true, anchor = Anchor { left = 0, right = 0, top = 26, bottom = 0 }, NotifyPageOpened = PageOpened, OnOpen = OnOpen };
// File Menu
menu = Menu {};
Menu fileMenu { menu, "File", f };
MenuItem newWindowItem
{
fileMenu, "New Window\tCtrl+N", n, ctrlN;
bool NotifySelect(MenuItem selection, Modifiers mods)
{
Explorer { state = normal }.Create();
return true;
}
};
MenuItem openItem
{
fileMenu, "Open...\tCtrl+O", o, ctrlO;
bool NotifySelect(MenuItem selection, Modifiers mods)
{
if(openFileDialog.Modal() == ok)
Go(openFileDialog.filePath);
return true;
}
};
// MenuItem closeItem { fileMenu, "Close\tCtrl-F4", c, NotifySelect = MenuFileClose };
MenuDivider { fileMenu };
MenuItem saveAsItem
{
fileMenu, "Save As...";
bool NotifySelect(MenuItem selection, Modifiers mods)
{
char fileName[MAX_LOCATION];
GetLastDirectory(htmlView.location, fileName);
strcpy(fileName, saveFileDialog.currentDirectory);
PathCat(fileName, fileName);
saveFileDialog.filePath = fileName;
if(saveFileDialog.Modal() == ok)
{
File f = FileOpen(htmlView.location, read);
if(f)
{
if(!f.CopyTo(saveFileDialog.filePath))
{
String e = PrintString("Error saving to ", saveFileDialog.filePath);
MessageBox { contents = e }.Modal();
delete e;
}
}
}
return true;
}
};
MenuDivider { fileMenu };
MenuItem exitItem { fileMenu, "Exit\tAlt+F4", x, NotifySelect = MenuFileExit };
bool PageOpened()
{
char caption[MAX_LOCATION];
strcpy(caption, "Ecere Web Browser - ");
strcat(caption, htmlView.title);
text = caption;
addressBar.address.Clear();
addressBar.address.PutS(htmlView.fileName);
return true;
}
bool OnPostCreate()
{
addressBar.MakeActive();
return true;
}
Array<String> history { };
int historyPos;
~Explorer()
{
history.Free();
}
bool HTMLView::OnOpen(char * href)
{
bool result = true;
char newLocation[MAX_LOCATION];
Explorer explorer = (Explorer)parent;
strcpy(newLocation, location ? location : "");
if(newLocation[strlen(newLocation)-1] != '/')
PathCat(newLocation, "..");
if(href[0] == '/' && href[1] == '/')
{
strcpy(newLocation, "http:");
strcat(newLocation, href);
}
else
PathCat(newLocation, href);
if(explorer.history.count > explorer.historyPos+1)
{
int i;
for(i = explorer.historyPos+1; i < explorer.history.count; i++)
delete explorer.history[i];
explorer.history.count = explorer.historyPos+1;
}
explorer.historyPos = explorer.history.count-1;
explorer.addressBar.back.disabled = (explorer.historyPos == 0);
explorer.addressBar.forward.disabled = (explorer.historyPos >= explorer.history.count-1);
Open(newLocation, null);
explorer.history.Add(CopyString(location));
explorer.historyPos = explorer.history.count-1;
explorer.addressBar.back.disabled = (explorer.historyPos == 0);
explorer.addressBar.forward.disabled = (explorer.historyPos >= explorer.history.count-1);
return result;
}
void Go(const String location)
{
if(history.count > historyPos+1)
{
int i;
for(i = historyPos+1; i < history.count; i++)
delete history[i];
history.count = historyPos+1;
}
history.Add(CopyString(location));
historyPos = history.count-1;
addressBar.back.disabled = (historyPos == 0);
addressBar.forward.disabled = (historyPos >= history.count-1);
htmlView.MakeActive();
htmlView.location = location;
}
void Refresh()
{
htmlView.MakeActive();
if(history.count)
htmlView.location = history[historyPos];
}
bool Forward()
{
if(historyPos < history.count-1)
{
historyPos++;
addressBar.back.disabled = (historyPos == 0);
addressBar.forward.disabled = (historyPos >= history.count-1);
htmlView.location = history[historyPos];
return true;
}
return false;
}
bool Back()
{
if(historyPos > 0)
{
historyPos--;
addressBar.back.disabled = (historyPos == 0);
addressBar.forward.disabled = (historyPos >= history.count-1);
htmlView.location = history[historyPos];
return true;
}
return false;
}
bool OnKeyHit(Key key, unichar ch)
{
if(key == ctrlR)
{
Refresh();
return false;
}
return true;
}
}
#ifndef ECERE_MODULE
class BrowserApp : GuiApplication
{
//driver = "OpenGL";
Explorer explorerWindow {};
bool Init()
{
app = this;
#ifndef ECERE_MODULE
if(argc > 1)
explorerWindow.Go(argv[1]);
else
#endif
explorerWindow.Go(homeLocation);
return true;
}
}
BrowserApp app;
#else
extern GuiApplication app;
#endif
import "ecere"
class Form1 : Window
{
text = "Form1";
background = activeBorder;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
size = { 640, 480 };
Button button1
{
this, text = "button1", position = { 240, 176 };
bool NotifyClicked(Button button, int x, int y, Modifiers mods)
{
MessageBox { contents = "Hello, world!" }.Modal();
return true;
}
};
}
Form1 form1 {};
#include <stdio.h>
struct Vector
{
float x, y;
};
bool FloatToString(char * string, float * value)
{
char * end;
*value = (float)strtod(string, &end);
return end > string;
}
char GetOperation()
{
char operation = 0;
PrintLn("Chose an operation to perform: +, -, *, /, m (module/length). q to quit.");
do
{
char input[1024];
gets(input);
switch(input[0])
{
case '+': case '-': case '*': case '/': case 'm': case 'q':
operation = input[0];
break;
default:
PrintLn("Invalid Operation");
}
} while(!operation);
return operation;
}
float GetScalar()
{
float scalar;
char input[1024];
gets(input);
while(!FloatToString(input, &scalar))
{
PrintLn("Print enter a valid numeric value");
gets(input);
}
return scalar;
}
Vector GetVector()
{
Vector vector;
char input[1024];
gets(input);
while(!vector.OnGetDataFromString(input))
{
PrintLn("Print enter a valid 2D vector value");
gets(input);
}
return vector;
}
class Lab5VectorApp : Application
{
void Main()
{
while(true)
{
Vector vector1, vector2;
float scalar;
char operation = GetOperation();
if(operation == 'q') break;
PrintLn("Enter the first operand:");
vector1 = GetVector();
if(operation != 'm')
{
PrintLn("Enter the second operand:");
if(operation == '+' || operation == '-')
vector2 = GetVector();
else
scalar = GetScalar();
}
if(operation == '/' && scalar == 0)
PrintLn("Cannot divide by 0");
else
{
switch(operation)
{
case '+': PrintLn(vector1, " + ", vector2, " = ", Vector { vector1.x + vector2.x, vector1.y + vector2.y }); break;
case '-': PrintLn(vector1, " - ", vector2, " = ", Vector { vector1.x - vector2.x, vector1.y - vector2.y }); break;
case '*': PrintLn(vector1, " * ", scalar, " = ", Vector { vector1.x * scalar, vector1.y * scalar }); break;
case '/': PrintLn(vector1, " / ", scalar, " = ", Vector { vector1.x / scalar, vector1.y / scalar }); break;
case 'm': PrintLn("|",vector1,"| = ", sqrt(vector1.x * vector1.x + vector1.y * vector1.y)); break;
}
}
}
system("pause");
}
}
#include <stdio.h>
enum KnownColor
{
black = 0,
red = 0xFF0000,
green = 0x00FF00,
blue = 0x0000FF,
yellow = 0xFFFF00,
magenta = 0xFF00FF,
cyan = 0x00FFFF,
white = 0xFFFFFF,
};
char GetOperation()
{
char operation = 0;
PrintLn("Chose an operation to perform: +, -. q to quit.");
do
{
char input[1024];
gets(input);
switch(input[0])
{
case '+': case '-': case 'q':
operation = input[0];
break;
default:
PrintLn("Invalid Operation");
}
} while(!operation);
return operation;
}
KnownColor GetOperand()
{
KnownColor operand;
char input[1024];
gets(input);
while(!operand.OnGetDataFromString(input))
{
PrintLn("Please enter a known color (black, red, green, blue, yellow, magenta, cyan or white)");
gets(input);
}
return operand;
}
KnownColor ComputeOperation(char operation, KnownColor operand1, KnownColor operand2)
{
switch(operation)
{
case '+': return operand1 + operand2;
case '-': return (KnownColor)(operand1 - operand2);
}
return 0;
}
class Lab5ColorsApp : Application
{
void Main()
{
while(true)
{
KnownColor operand1, operand2;
char operation = GetOperation();
if(operation == 'q') break;
PrintLn("Enter the first operand:");
operand1 = GetOperand();
PrintLn("Enter the second operand:");
operand2 = GetOperand();
{
KnownColor result = ComputeOperation(operation, operand1, operand2);
PrintLn(operand1, " ", operation, " ", operand2, " = ", result);
}
}
system("pause");
}
}
import "ecere"
#include <stdio.h>
class Spell
{
public:
int difficulty;
int damage;
int manaCost;
virtual void Backfire(Creature self, Creature opponent)
{
self.health -= damage/4;
}
virtual void Success(Creature self, Creature opponent)
{
if(damage > opponent.health) damage = opponent.health;
PrintLn(self._class.name, " did ", damage, " damage to ", opponent._class.name, ".");
opponent.health -= damage;
}
}
class FireBall : Spell { difficulty = 20, damage = 8; manaCost = 5; };
class Lightning : Spell { difficulty = 10, damage = 4; manaCost = 3; };
class Healing : Spell
{
difficulty = 20;
manaCost = 5;
void Success(Creature self, Creature opponent)
{
self.health += self.maxHealth / 5;
if(self.health > self.maxHealth) self.health = self.maxHealth;
}
void Backfire(Creature self, Creature opponent)
{
self.health -= damage/4;
}
};
class Creature
{
public:
int xp;
int health, maxHealth;
int mana, maxMana;
int dexterity;
int magic;
int strength;
int gold;
Array<Spell> spells;
Array<Equipment> equipment;
void CastSpell(Spell spell, Creature opponent)
{
if(mana >= spell.manaCost)
{
int r = GetRandom(0, spell.difficulty);
mana -= spell.manaCost;
if(magic >= r)
{
PrintLn(_class.name, " cast ", spell._class.name, " successfully.");
spell.Success(this, opponent);
}
else if(r > magic * 2)
{
PrintLn(_class.name, "'s ", spell._class.name, " backfired.");
spell.Backfire(this, opponent);
}
else
PrintLn(_class.name, " unsucessfully cast ", spell._class.name, ".");
}
}
void Attack(Creature opponent)
{
Weapon weapon = (Weapon)(equipment ? equipment[EquipmentSlot::rightHand] : null);
int d, r, o;
if(!weapon) weapon = bareHand;
o = GetRandom(0, opponent.dexterity);
d = GetRandom(0, dexterity - weapon.difficulty);
if(d > o)
{
int d = GetRandom(1, strength);
int where = GetRandom(0, 100);
int armor = 0;
int howBad = 0;
EquipmentSlot slot;
int damage;
if(where < 60)
{
slot = body;
howBad = 2;
}
else if(where < 80)
{
slot = head;
howBad = 3;
}
else if(where < 95)
{
slot = legs;
howBad = 1;
}
else
{
slot = feet;
howBad = 1;
}
if(opponent.equipment && opponent.equipment[slot])
armor = ((Armor)opponent.equipment[slot]).decDamage;
damage = Max(1, (d * weapon.damage - armor) * howBad / 10);
if(damage > opponent.health) damage = opponent.health;
opponent.health -= damage;
PrintLn(_class.name, " did ", damage, " damage to ", opponent._class.name, ".");
}
else
PrintLn(_class.name, " missed.");
}
}
Weapon bareHand { difficulty = 3, damage = 1 };
enum EquipmentSlot { leftHand, rightHand, head, feet, body, legs, ring, ring2, ring3, ring4 };
class Equipment
{
public:
int value;
EquipmentSlot slot;
bool twoHands;
virtual void Show();
}
class Armor : Equipment
{
public:
int decDamage;
void Show()
{
Print("Damage -", decDamage);
}
}
class Weapon : Equipment
{
public:
int difficulty;
int damage;
void Show()
{
Print("Difficulty: ", difficulty, ", Damage +", damage);
}
}
class LightShield : Armor { decDamage = 2; slot = leftHand; value = 20; };
class HeavyShield : Armor { decDamage = 5; slot = leftHand; value = 100; };
class Helmet : Armor { decDamage = 5; slot = head; value = 60; };
class SteelBoots : Armor { decDamage = 2; slot = feet; value = 40; };
class LightArmor : Armor { decDamage = 4; slot = body; value = 40; };
class PlateArmor : Armor { decDamage = 8; slot = body; value = 150; };
class PlateLeggings : Armor { decDamage = 3; slot = legs; value = 50; };
class Dagger : Weapon { difficulty = 2, damage = 2, value = 10, slot = rightHand; };
class LongSword : Weapon { difficulty = 4, damage = 4, value = 40, slot = rightHand; };
class BattleSword : Weapon { difficulty = 8, damage = 10, value = 100, slot = rightHand, twoHands = true; };
class Slug : Creature { xp = 10; maxHealth = 10; dexterity = 7; strength = 5; gold = 1; }
class GiantRat : Creature { xp = 30; maxHealth = 20; dexterity = 9; strength = 8; gold = 3; }
class GiantSpider : Creature { xp = 50; maxHealth = 30; dexterity = 20; strength = 10; gold = 4; }
class Bat : Creature { xp = 70; maxHealth = 10; dexterity = 40; strength = 5; gold = 6; }
class Goblin : Creature
{
xp = 120; maxHealth = 50; dexterity = 50; strength = 25; gold = 10;
}
class Ghoul : Creature { xp = 250; maxHealth = 70; dexterity = 20; strength = 30; gold = 30; }
class DarkKnight : Creature
{
xp = 500; maxHealth = 100; dexterity = 50; strength = 50; gold = 50; magic = 30; maxMana = 50;
spells = { [ FireBall { } ] };
equipment = { [ HeavyShield { }, LongSword { }, Helmet { }, SteelBoots { }, PlateArmor { }, PlateLeggings { }, null, null, null, null ] };
};
Array<Class> badGuys { [ class(Slug), class(GiantRat), class(GiantSpider), class(Goblin), class(Bat), class(DarkKnight), class(Ghoul) ] };
class EvilSorcerer : Creature
{
xp = 1000; maxHealth = 1000; dexterity = 75; strength = 50; gold = 20000; magic = 50; maxMana = 500;
equipment = { [ HeavyShield { }, LongSword { }, Helmet { }, SteelBoots { }, PlateArmor { }, PlateLeggings { }, null, null, null, null ] };
spells = { [ FireBall { }, Lightning { }, Healing { } ] };
}
Array<Equipment> shopInventory
{
[
Dagger { },
LongSword { },
BattleSword { },
LightShield { },
HeavyShield { },
Helmet { },
SteelBoots { },
LightArmor { },
PlateArmor { },
PlateLeggings { }
]
};
enum GameState { realm, shop, fight, training, sorcerer, end };
class Player : Creature
{
public:
int manaPotions;
int healthPotions;
int training;
spells = { [ FireBall { }, Lightning { }, Healing { } ] };
equipment = { [ null, null, null, null, null, null, null, null, null, null ] };
}
Player player { xp = 0, maxHealth = 40, health = 40, mana = 20, maxMana = 20, magic = 10, strength = 10, dexterity = 10, gold = 50, training = 2 };
Creature opponent;
class RPGApp : Application
{
GameState state;
char command[1024];
void PrintStatus()
{
PrintLn("");
switch(state)
{
case sorcerer:
case fight:
PrintLn("You are fighting a ", opponent._class.name);
PrintLn(opponent._class.name, "'s Health: ", opponent.health, "/",opponent.maxHealth);
PrintLn("Your Health: ", player.health, "/", player.maxHealth, ", Mana: ", player.mana, "/",player.maxMana);
PrintLn("[A]ttack");
PrintLn("[R]un");
if(player.healthPotions)
PrintLn("[H]ealth potion");
if(player.manaPotions)
PrintLn("[M]ana potion");
if(player.spells.count)
{
int n = 1;
PrintLn("Cast a spell:");
for(s : player.spells)
PrintLn(" ", n++, ". ", s._class.name);
}
break;
case shop:
{
int n = 1;
PrintLn("Welcome to the village shop! What could we interest you in?");
PrintLn(" [H]ealth potions (10) [M]ana potions (15) Go [B]ack to the realm");
PrintLn(" You have ", player.gold, " gold coins");
for(i : shopInventory)
{
Print(" ", n++, ". ", i._class.name, ": ");
i.Show();
PrintLn(" (", i.value, ")");
}
break;
}
case realm:
PrintLn("You are wandering in the realm. What would you like to do?");
PrintLn("[F]ight bad guys Visit the [S]hop [R]est St[a]ts");
if(player.xp >= 1000)
PrintLn("Are you ready to rescue the [P]rincess?");
if(player.training)
PrintLn("Do you want to [T]rain? You have ", player.training, " training points.");
break;
case training:
PrintLn("You have ", player.training, " training points. What would you like to improve?");
PrintLn("[H]ealth");
PrintLn("[M]ana");
PrintLn("[S]trength");
PrintLn("[D]exterity");
PrintLn("Ma[g]ic");
PrintLn(" Go [B]ack to the realm");
break;
}
}
void GetCommand()
{
gets(command);
strlwr(command);
}
bool AreYouSure()
{
char input[1024];
gets(input);
strlwr(command);
return input[0] == 'y';
}
void OpponentAttacks()
{
if(opponent.health > 0 && player.health > 0)
{
if(opponent.spells && opponent.spells.count && opponent.mana > opponent.maxMana / 5)
{
if(GetRandom(0,1) == 1)
{
int s = GetRandom(0, opponent.spells.count-1);
if(opponent.mana >= opponent.spells[s].manaCost)
opponent.CastSpell(opponent.spells[s], player);
else
opponent.Attack(player);
}
else
opponent.Attack(player);
}
else
opponent.Attack(player);
}
if(player.health <= 0)
{
PrintLn("You died :(");
state = end;
}
else if(opponent.health <= 0)
{
int trainingPointsBefore = player.xp / 50;
PrintLn("Congratulations! You won the fight. You gained ", opponent.xp/10, " xp points and ", opponent.gold, " gold.");
player.gold += opponent.gold;
player.xp += opponent.xp / 10;
player.training += player.xp / 50 - trainingPointsBefore;
delete opponent;
if(state == sorcerer)
PrintLn("You saved the princess!! The end.");
state = realm;
}
}
void FindOpponent()
{
while(true)
{
int c = GetRandom(0, badGuys.count-1);
opponent = eInstance_New(badGuys[c]);
if(opponent.xp < 40 || opponent.xp <= player.xp)
break;
delete opponent;
}
opponent.health = opponent.maxHealth;
opponent.mana = opponent.maxMana;
state = fight;
}
void ProcessCommand()
{
if(command[0] == 'q')
{
PrintLn("Are you sure you want to quit?");
if(AreYouSure())
state = end;
}
switch(state)
{
case shop:
switch(command[0])
{
case 'b': state = realm; break;
case 'm': case 'h':
{
int price = (command[0] == 'm') ? 15 : 10;
if(player.gold < price)
PrintLn("You do not have enough gold!");
else
{
(command[0] == 'm') ? player.manaPotions++ : player.healthPotions++;
player.gold -= price;
}
break;
}
default:
{
int item = atoi(command);
if(item && item <= shopInventory.count)
{
Equipment eq = shopInventory[item-1];
EquipmentSlot slot = eq.slot;
int tradeIn;
Equipment tradeIn1 = null, tradeIn2 = null;
if(slot == ring)
while(player.equipment[slot] && slot < ring4)
slot++;
if(slot == rightHand && eq.twoHands)
{
if(player.equipment[EquipmentSlot::leftHand])
tradeIn1 = player.equipment[EquipmentSlot::leftHand];
if(player.equipment[EquipmentSlot::rightHand])
tradeIn2 = player.equipment[EquipmentSlot::rightHand];
}
else if((slot == leftHand || slot == rightHand) && player.equipment[EquipmentSlot::rightHand] && player.equipment[EquipmentSlot::rightHand].twoHands)
{
if(player.equipment[EquipmentSlot::rightHand])
tradeIn1 = player.equipment[EquipmentSlot::rightHand];
}
else if(player.equipment[slot])
tradeIn1 = player.equipment[slot];
tradeIn = ((tradeIn1 ? tradeIn1.value : 0) + (tradeIn2 ? tradeIn2.value : 0)) / 2;
if(player.gold + tradeIn < eq.value)
PrintLn("You do not have enough gold!");
else
{
if(player.equipment[slot])
PrintLn("You will need to trade in your ", player.equipment[slot]._class.name, ", for ", tradeIn, ".");
PrintLn("Are you sure you want to buy this ", eq._class.name, " for ", eq.value, "?");
if(AreYouSure())
{
if(tradeIn1) shopInventory.Add(tradeIn1);
if(tradeIn2) shopInventory.Add(tradeIn2);
player.equipment[slot] = eq;
player.gold += tradeIn - eq.value;
shopInventory.Remove(shopInventory.Find(eq));
//shopInventory.TakeOut(eq);
}
}
}
}
}
break;
case fight:
case sorcerer:
{
bool fightBack = false;
switch(command[0])
{
case 0:
case 'a':
player.Attack(opponent);
fightBack = true;
break;
case 'm':
if(player.manaPotions)
{
player.manaPotions--;
player.mana += player.maxMana / 5;
if(player.mana > player.maxMana) player.mana = player.maxMana;
}
break;
case 'h':
if(player.healthPotions)
{
player.healthPotions--;
player.health += player.maxHealth / 5;
if(player.health > player.maxHealth) player.health = player.maxHealth;
}
break;
case 'r':
OpponentAttacks();
if(player.health > 0)
state = realm;
break;
default:
{
int item = atoi(command);
if(item && item <= player.spells.count)
{
if(player.mana >= player.spells[item-1].manaCost)
{
player.CastSpell(player.spells[item-1], opponent);
fightBack = true;
}
else
PrintLn("Not enough mana to cast that spell.");
}
}
}
if(fightBack)
OpponentAttacks();
break;
}
case realm:
switch(command[0])
{
case 'a':
{
EquipmentSlot c;
PrintLn("\nYour statistics:");
PrintLn("XP: ", player.xp);
PrintLn("Health: ", player.health, "/", player.maxHealth);
PrintLn("Mana: ", player.mana, "/", player.maxMana);
PrintLn("Strength: ", player.strength, ", Dexterity: ", player.dexterity, ", Magic: ", player.magic);
PrintLn("Gold: ", player.gold);
PrintLn("Equipment:");
for(c = leftHand; c <= ring4; c++)
{
Equipment eq = player.equipment[c];
if(eq)
{
Print(c, ": ", eq._class.name, ": ");
eq.Show();
PrintLn("");
}
}
if(player.manaPotions)
PrintLn(player.manaPotions, " mana potions");
if(player.healthPotions)
PrintLn(player.healthPotions, " health potions");
if(player.training)
PrintLn(player.training, " training points");
break;
}
case 's': state = shop; break;
case 'b': state = realm; break;
case 'f': FindOpponent(); break;
case 't': state = training; break;
case 'p':
if(player.xp > 1000)
{
opponent = EvilSorcerer { };
state = sorcerer;
}
break;
case 0:
case 'r':
if(GetRandom(0, 3) == 0)
{
PrintLn("Your rest was interrupted!");
FindOpponent();
OpponentAttacks();
}
else
{
player.health += player.maxHealth / 5;
if(player.health > player.maxHealth) player.health = player.maxHealth;
player.mana += player.maxMana / 5;
if(player.mana > player.maxMana) player.mana = player.maxMana;
}
break;
}
break;
case training:
{
bool valid = true;
switch(command[0])
{
case 'h': player.health += player.maxHealth / 5; player.maxHealth += player.maxHealth / 5; break;
case 'm': player.mana += player.maxMana / 5; player.maxMana += player.maxMana / 5; break;
case 's': player.strength += player.strength / 5; break;
case 'd': player.dexterity += player.dexterity / 5; break;
case 'g': player.magic += player.magic / 5; break;
case 'b': state = realm;
default: valid = false;
}
if(valid)
{
player.training--;
if(!player.training)
state = realm;
}
break;
}
}
}
void Main()
{
RandomSeed((uint)(GetTime()*1000));
PrintLn("Welcome to this great minimalist RPG!");
PrintLn("You will need to save the princess from an Evil Sorcerer.");
PrintLn("But first you should wander the realm to fight the sorcerer's minions, ");
PrintLn("gaining experience and equipment in the process. You will need to reach");
PrintLn("at least 1000 experience points to search for the sorcerer's hideout.");
PrintLn("At any time you can [Q]uit.");
while(state != end)
{
PrintStatus();
GetCommand();
ProcessCommand();
}
system("pause");
}
}