#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define DEFAULT_PORT "27015"
#define DEFAULT_BUFLEN 512
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <process.h>
FILE *users;//user database file for account making and logging in
FILE *usernames;//list of taken usernames
struct user {
SOCKET connection;//socket user is connected to
char username[20];//their username
};
struct user *connecters;//dynamic list of connected users
int length=0;//length of connected users
struct user* remove_element(struct user* array, int sizeOfArray, int indexToRemove){
struct user* temp = malloc((sizeOfArray - 1) * sizeof(struct user)); // allocate an array with a size 1 less than the current one
if (indexToRemove != 0)
memcpy(temp, array, indexToRemove * sizeof(struct user)); // copy everything BEFORE the index
if (indexToRemove != (sizeOfArray - 1))
memcpy(temp+indexToRemove, array+indexToRemove+1, (sizeOfArray - indexToRemove - 1) * sizeof(struct user)); // copy everything AFTER the index
free (array);
return temp;
}
unsigned __stdcall ClientSession(void *data){//multithreading, gonna be real with you I have no idea how this code works
SOCKET ClientSocket = (SOCKET)data;// Process the client.
//message receiving setup stuff
char message[DEFAULT_BUFLEN];
int buffer;//function recorder
int buffer2;//another function recorder
int iSendResult;
int messageSize = DEFAULT_BUFLEN;
char sender[100];//user that is sending stuff
//login shit
bool logger=false;
char accounter[1];//records if they have an account
do {//it has to be a do while so the thread ends properly
buffer2=recv(ClientSocket, accounter, 1, 0);//checking if they need to make a new account or can log in
printf("%d\n",buffer2);
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (accounter[0]=='N'){
users=fopen("users.txt","a");//opens the user recording file
char holder[2][20];//holds the login info
while (true){
usernames=fopen("usernames.txt","r");//opens the username list file
bool taken=false;
buffer2=recv(ClientSocket, holder[0], 20, 0);//getting the username
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (strcmp(holder[0]," ")==0){//checks if it's just a timeout space
memset(holder[0], 0, sizeof(holder[0]));//resetting login info if it's just a space
continue;
}
//checks if the username is taken
char checker[100];
while(fgets(checker, 100, usernames)) {
if (checker[strlen(checker)-1]== '\n') checker[strlen(checker)-1]='\0';
if (strcmp(checker,holder[0])==0){
taken=true;
char denier[]="taken";
send(ClientSocket, denier, (int)strlen(denier), 0);
break;
}
}
fclose(usernames);
if (taken) continue;
char accepter[]="okie-dokie";
send(ClientSocket, accepter, (int)strlen(accepter), 0);
break;
}
while (true){
buffer2=recv(ClientSocket, holder[1], 20, 0);//getting the login info
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (strcmp(holder[1]," ")==0){
memset(holder[1], 0, sizeof(holder[1]));//resetting login info if it's just a space
continue;
}
break;
}
//recording the new account
char account[] = " username: ";
strcat(account,holder[0]);
strcat(account," password: ");
strcat(account,holder[1]);
strcat(account,"\n");
fprintf(users,account);//recording login info
strcat(holder[0],"\n");
usernames=fopen("usernames.txt","a");
fprintf(usernames,holder[0]);//recording the username
fclose(users);
fclose(usernames);
}
if (accounter[0]=='Y'){
char holder[2][20];//stores login info
while (true){
buffer2=recv(ClientSocket, holder[0], 20, 0);//getting the login info
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (strcmp(holder[0]," ")==0){
memset(holder[0], 0, sizeof(holder[0]));//resetting login info if it's just a space
continue;
}
break;
}
while (true){
buffer2=recv(ClientSocket, holder[1], 20, 0);//getting the login info
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (strcmp(holder[1]," ")==0){
memset(holder[1], 0, sizeof(holder[1]));//resetting login info if it's just a space
continue;
}
break;
}
char account[] = " username: ";
strcat(account,holder[0]);
strcat(account," password: ");
strcat(account,holder[1]);
printf("%s\n",account);
char accountBuffer[100];
bool noper=false;
users=fopen("users.txt","r");
while (fgets(accountBuffer, 100, users)){
if (accountBuffer[strlen(accountBuffer)-1]== '\n') accountBuffer[strlen(accountBuffer)-1]='\0';//checks if last character is newline
if (strcmp(account,accountBuffer)==0){
//login confirmation stuff
logger=true;
send(ClientSocket, "Y", 1, 0);//yes they logged in right
printf("Logged in\n");
length++;
connecters=realloc(connecters,length*sizeof(struct user));
struct user newGuy = {
.connection=ClientSocket
};
memcpy(newGuy.username, holder[0], 20);
connecters[length-1]=newGuy;
fclose(users);
strcpy(sender,holder[0]);
noper=true;
break;
}
}
if (!noper) send(ClientSocket, "N", 1, 0);//no they logged in wrong
memset(holder[0], 0, sizeof(holder[0]));//resetting the login info
memset(holder[1], 0, sizeof(holder[1]));//resetting the login info
}
} while (!logger&&buffer2>0);//making it so the thread ends properly if connection is insantly abandoned
// Receive until the peer shuts down the connection
do {
memset(message, 0, sizeof(message));//resetting the message
buffer = recv(ClientSocket, message, messageSize, 0);//receiving the message
if (buffer > 0) {
if (strcmp(message," ")==0) continue;
printf("%s\n",message);//prints message they sent
char receiver[50];
memset(receiver, 0, sizeof(receiver));//resetting this because for some reason it doesn't work when I don't
while (true){
buffer2=recv(ClientSocket, receiver, 20, 0);//receiving the receiver
if (!(buffer2>=0)){
printf("recv failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
if (strcmp(receiver," ")==0){
memset(receiver, 0, sizeof(receiver));//resetting the receiver if it's just a space
continue;
}
break;
}
//searches for user to send the message to
for (int i=0;i<length;i++){
if (strcmp(connecters[i].username,receiver)==0){
iSendResult = send(connecters[i].connection, sender, sizeof(sender), 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
//send message to correct person
iSendResult = send(connecters[i].connection, message, sizeof(message), 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ClientSocket);
return 1;
}
}
}
} else if (buffer == 0)
printf("Connection closing...\n");
else {
printf("recv failed: %d\n", WSAGetLastError());
for (int i=0;i<length;i++){
if (connecters[i].connection==ClientSocket&&strcmp(connecters[i].username,sender)==0){
connecters = remove_element(connecters, length, i);
length--;
}
}
closesocket(ClientSocket);
return 1;
}
} while (buffer > 0);
//removing them from the list
for (int i=0;i<length;i++){
if (connecters[i].connection==ClientSocket&&strcmp(connecters[i].username,sender)==0){
connecters = remove_element(connecters, length, i);
length--;
}
}
closesocket(ClientSocket);
printf("thread ended\n");
return 0;
}
int main(){
connecters=(struct user*)malloc(length * sizeof(struct user));//list of connected users
//winsock setup variables
WSADATA wsaData;
int buffer;
struct sockaddr_in service;//struct that stores ip address
// Initialize Winsock
buffer = WSAStartup(MAKEWORD(2,2), &wsaData);
if (buffer != 0) {
printf("WSAStartup failed: %d\n", buffer);
return 1;
}
// Create a SOCKET for listening for
// incoming connection requests
SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket function failed with error: %u\n", WSAGetLastError());
WSACleanup();
return 1;
}
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("172.16.226.210");//ip to bind to
service.sin_port = htons(27015);//port
// Bind the socket.
buffer = bind(ListenSocket, (SOCKADDR *) &service, sizeof (service));
if (buffer == SOCKET_ERROR) {
wprintf(L"bind failed with error %u\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//listening for incoming socket
while (true){
if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) {
printf( "Listen failed with error: %d\n", WSAGetLastError() );
closesocket(ListenSocket);
WSACleanup();
return 1;
}
SOCKET ClientSocket;
ClientSocket = INVALID_SOCKET;
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
printf("%llu\n",ClientSocket);//printing the client socket
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Create a new thread for the accepted client (also pass the accepted client socket).
unsigned threadID;
(HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID);
}
// cleanup
WSACleanup();
printf("socket adventures");
return 0;
}
This is server for a messaging app written in pure C using the winsock library. It has a login system that allows users to sign in with a username of their choice (provided that username isn't taken) and password. It also has an address system that determines which users are signed in. The app works by a user sending a message, indicating who they want to send the message to, and the server sends that message to the person addressed, provided they are online and signed in. A very simple but effective chat app, similar to the chat apps of the early 90s. The server runs based off a custom database design and remembers login infos long after the client signs off, or the server goes down. A lot of this was difficult to design as I had to work with both the client and server side of things simultaneously. I always find myself coming back to this project to add more features and whatnot.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <process.h>
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#define PI atan(1)*4
char lastMessage[100];
//circle maker
void drawCircle(SDL_Renderer *renderer, int x, int y, int radius){
for (int w = 0; w < radius * 2; w++) {
for (int h = 0; h < radius * 2; h++) {
int dx = radius - w; // horizontal offset
int dy = radius - h; // vertical offset
if ((dx*dx + dy*dy) <= (radius * radius)) SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
void delay(int number_of_seconds){
int milli_seconds = 1000 * number_of_seconds;// Converting time into milli_seconds
clock_t start_time = clock();// Storing start time
while (clock() < start_time + milli_seconds);// looping till required time is not achieved
}
unsigned __stdcall ClientSession(void *data){//multithreading to stop timeout bug
SOCKET ConnectSocket = (SOCKET)data;// Process the client.
char message[]=" ";//blank message to send server
int buffer;
while (true){
delay(240);//delay of 4 minutes
buffer = send( ConnectSocket, message, (int)strlen(message), 0 );//sending server a blank message to keep connection going
if (buffer == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
}
return 0;
}
unsigned __stdcall messageListener(void *data){//multithreading to receive messages
SOCKET ConnectSocket = (SOCKET)data;// Process the client.
char message[DEFAULT_BUFLEN];//message holder
char sender[50];
int buffer;
while (true){
recv(ConnectSocket, sender, DEFAULT_BUFLEN, 0);//getting the user
recv(ConnectSocket, message, DEFAULT_BUFLEN, 0);//getting the message
strcat(sender," : ");
strcat(sender,message);
memset(lastMessage,0,sizeof(lastMessage));
strcpy(lastMessage,sender);
memset(message, 0, sizeof(message));//resetting the message
memset(sender, 0, sizeof(sender));//resetting the message
}
return 0;
}
const int width=1024,height=576;//screen proportions
int main(int argc,char **argv){
strcpy(lastMessage,"");
//SDL setup stuff
bool quit = false;
SDL_Event event;
SDL_Init( SDL_INIT_EVERYTHING );
IMG_Init(IMG_INIT_PNG);
IMG_Init(IMG_INIT_JPG);
TTF_Init();
//winsock stuff
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;// connecting socket
char message[DEFAULT_BUFLEN];//message holder
char receive[DEFAULT_BUFLEN];//received message storage
int buffer;
// Initialize Winsock
buffer = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (buffer != NO_ERROR) {
wprintf(L"WSAStartup function failed with error: %d\n", buffer);
return 1;
}
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
wprintf(L"socket function failed with error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
struct sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("172.16.226.210");//where it's connecting
clientService.sin_port = htons(27015);//port
// Connect to server.
buffer = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService));
if (buffer == SOCKET_ERROR) {
wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
buffer = closesocket(ConnectSocket);
if (buffer == SOCKET_ERROR)
wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//setting up timeout prevention
unsigned threadID;
(HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ConnectSocket, 0, &threadID);
//end of client setup stuff
SDL_Window * window = SDL_CreateWindow("messaging app",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);//creating a window
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);//creating the renderer
SDL_Surface * screen=SDL_CreateRGBSurface(0,width,height,32,0,0,0,0);
TTF_Font* Sans = TTF_OpenFont("The Wild Breath of Zelda.otf", 24);//setting up the font
SDL_Surface * icon=IMG_Load("penisforeskinicon.JPG");//icon
SDL_Color black = {0, 0, 0};
SDL_SetRenderDrawColor(renderer,20,0,123,0);
char input[DEFAULT_BUFLEN];
strcpy(input,"");
char prompt[100];
strcpy(prompt,"do you have an account? Enter Y for yes, or N for no" );
char screenType[20];
strcpy(screenType,"login");
//login variables
bool logger=false;
char login[2][20];
char accounter[1];
char text[100];//message
//universal screen rects
SDL_Rect topbar;
topbar.y=0;
topbar.x=0;
topbar.h=80;
topbar.w=width;
SDL_Rect titleRect; //create a rect
titleRect.w = 100; // controls the width of the rect
titleRect.h = 60; // controls the height of the rect
titleRect.x = width/2 -titleRect.w/2; //controls the rect's x coordinate
titleRect.y = topbar.y+15; // controls the rect's y coordinte
SDL_Rect bottombar;
bottombar.y=height-20;
bottombar.x=0;
bottombar.h=20;
bottombar.w=width;
SDL_Rect sq1;
sq1.w=100;
sq1.h=60;
sq1.x=topbar.x+20;
sq1.y=topbar.y+10;
SDL_Rect sq2;
sq2.w=100;
sq2.h=60;
sq2.x=sq1.x+sq1.w+20;
sq2.y=topbar.y+10;
SDL_Rect sq3;
sq3.w=100;
sq3.h=60;
sq3.x=sq2.x+sq2.w+20;
sq3.y=topbar.y+10;
SDL_Rect sq4;
sq4.w=100;
sq4.h=60;
sq4.x=topbar.w-sq4.w-20;
sq4.y=topbar.y+10;
SDL_Rect sq5;
sq5.w=100;
sq5.h=60;
sq5.x=sq4.x-sq5.w-20;
sq5.y=topbar.y+10;
SDL_Rect sq6;
sq6.w=100;
sq6.h=60;
sq6.x=sq5.x-sq6.w-20;
sq6.y=topbar.y+10;
SDL_Rect squares[]={sq1,sq2,sq3,sq4,sq5,sq6};
//login screen rects
SDL_Rect loginSquare;
loginSquare.w=400;
loginSquare.h=250;
loginSquare.x=width/2-loginSquare.w/2;
loginSquare.y=height/2-loginSquare.h/2;
SDL_Rect loginInput;
loginInput.w=70;
loginInput.h=70;
loginInput.x=loginSquare.x+loginSquare.w/2 -loginInput.w/2;
loginInput.y=loginSquare.h-loginInput.h/2;
SDL_Rect promptBox;
promptBox.w=10*strlen(prompt);
promptBox.h=40;
promptBox.x=loginSquare.x;
promptBox.y=loginSquare.y-50;
//messaging rects
SDL_Rect personBox;
personBox.w=width;
personBox.h=40;
personBox.x=0;
personBox.y=topbar.h;
SDL_Rect sendBox;
sendBox.w=400;
sendBox.h=550;
sendBox.x=40;
sendBox.y=height-10;
SDL_Rect label;
label.w=300;
label.h=60;
label.x=width/2-label.w/2;
label.y=personBox.y+personBox.h+20;
SDL_Rect m1;
m1.w=300;
m1.h=60;
m1.x=width/2-m1.w/2;
m1.y=height/2-m1.h/2+label.h;
//Enable text input
SDL_StartTextInput();
SDL_Event windowEvent;
SDL_SetWindowIcon(window, icon);
while (true){
if (SDL_PollEvent(&windowEvent)){
if (SDL_QUIT==windowEvent.type){
break;
}
}
if( windowEvent.type == SDL_KEYDOWN ){
//Handle backspace
if( windowEvent.key.keysym.sym == SDLK_BACKSPACE && strlen(input) > 0 ){
//lop off character
input[strlen(input)-1]='\0';
}
//handling enter button
if( windowEvent.key.keysym.sym == SDLK_RETURN && strlen(input) > 0 ){
//account input
if (strcmp(screenType,"login")==0&&strlen(accounter)==0&&strlen(input)!=0&&strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")==0){
if (strlen(input)!=1){
memset(input,0,sizeof(input));
strcpy(input,"");
strcpy(accounter,input);
} else {
memset(accounter,0,sizeof(accounter));
strcpy(accounter,input);
accounter[0]=toupper(accounter[0]);
}
if (accounter[0]=='N'||accounter[0]=='Y'){
bool newUsername=false;
memset(input,sizeof(input),0);
strcpy(input,"");
memset(prompt,sizeof(prompt),0);
if (accounter[0]=='Y') strcpy(prompt,"enter your username");
else strcpy(prompt,"create an account, enter your username");
promptBox.w=10*strlen(prompt);
send( ConnectSocket, accounter, 1, 0 );//sending if user wants to make new account
} else {
memset(input,0,sizeof(input));
strcpy(input,"");
strcpy(accounter,input);
}
//login info if you do have an account
} else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your username")==0){
strcpy(login[0],input);
send( ConnectSocket, login[0], sizeof(login[0]), 0 );//sending login info
memset(input,sizeof(input),0);
strcpy(input,"");
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"enter your password");
promptBox.w=10*strlen(prompt);
//login info if you do have an account password
} else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your password")==0&&accounter[0]=='Y'){
strcpy(login[1],input);
send( ConnectSocket, login[1], sizeof(login[1]), 0 );//sending login info
memset(input,sizeof(input),0);
strcpy(input,"");
recv(ConnectSocket, accounter, 1, 0);
if (accounter[0]=='Y'){
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"You're logged in!");
//message listening
unsigned listener;
(HANDLE)_beginthreadex(NULL, 0, &messageListener, (void*)ConnectSocket, 0, <istener);
promptBox.w=10*strlen(prompt);
} else {
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"Wrong login");
promptBox.w=10*strlen(prompt);
}
memset(login[0], 0, sizeof(login[0]));//resetting the login info
memset(login[1], 0, sizeof(login[1]));//resetting the login info
memset(accounter, 0, sizeof(accounter));//resetting the login info
//login if you're making an account username
} else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&(strcmp(prompt,"create an account, enter your username")==0||strcmp(prompt,"username taken, please pick a new one")==0)){
memset(login[0], 0, sizeof(login[0]));//resetting the login info
strcpy(login[0],input);
send( ConnectSocket, login[0], sizeof(login[0]), 0 );//sending login info
char checker[strlen("okie-dokie")+1];
recv(ConnectSocket, checker, strlen("okie-dokie"), 0);
printf(checker);
if (strcmp(checker,"okie-dokie")==0){
memset(input,sizeof(input),0);
strcpy(input,"");
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"enter your password");
promptBox.w=10*strlen(prompt);
} else {
memset(input,sizeof(input),0);
strcpy(input,"");
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"username taken, please pick a new one");
promptBox.w=10*strlen(prompt);
}
//account creation for no account
} else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your password")==0&&accounter[0]=='N'){
strcpy(login[1],input);
send( ConnectSocket, login[1], sizeof(login[1]), 0 );//sending login info
memset(input,sizeof(input),0);
strcpy(input,"");
memset(login[0], 0, sizeof(login[0]));//resetting the login info
memset(login[1], 0, sizeof(login[1]));//resetting the login info
memset(accounter, 0, sizeof(accounter));//resetting the login info
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"account created");
promptBox.w=10*strlen(prompt);
}
else if (strcmp(screenType,"messaging")==0&&strlen(input)!=0&&strcmp(prompt,"enter the message you want to send")==0){
memset(text,0,sizeof(text));
strcpy(text,input);
memset(input,0,sizeof(input));
strcpy(input,"");
// Sending a message
send( ConnectSocket, text, (int)strlen(text), 0 );
memset(prompt,0,sizeof(prompt));
strcpy(prompt,"who do you want to message?");
}
else if (strcmp(screenType,"messaging")==0&&strlen(input)!=0&&strcmp(prompt,"who do you want to message?")==0){
char receiver[40];
strcpy(receiver,input);
send( ConnectSocket, receiver, (int)strlen(receiver), 0 );//message
memset(input,sizeof(input),0);
strcpy(input,"");
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"enter the message you want to send");
}
}
}
//Special text input event
else if( windowEvent.type == SDL_TEXTINPUT ){
//Not copy or pasting
if( !( SDL_GetModState() & KMOD_CTRL && ( windowEvent.text.text[ 0 ] == 'c' || windowEvent.text.text[ 0 ] == 'C' || windowEvent.text.text[ 0 ] == 'v' || windowEvent.text.text[ 0 ] == 'V' ) ) )
{
//Append character
if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")==0&&strlen(input)==0) strcat( input,windowEvent.text.text);
else if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")!=0) strcat( input,windowEvent.text.text);
}
}
SDL_FillRect(screen,NULL,230219217);
SDL_FillRect(screen,&topbar,122241255);
SDL_FillRect(screen,&bottombar,122241255);
//coloring in the boxes for the login screen
if (strcmp(screenType,"login")==0){
SDL_FillRect(screen,<oginSquare,122241255);
SDL_FillRect(screen,<oginInput,255255255);
SDL_FillRect(screen,&promptBox,122241255);
}
if (strcmp(screenType,"messaging")==0){
SDL_FillRect(screen,&sendBox,255255255);
SDL_FillRect(screen,&personBox,255255255);
}
SDL_Texture * texture=SDL_CreateTextureFromSurface(renderer, screen);
SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background
SDL_Surface* title = TTF_RenderText_Solid(Sans, "HERMES", black);//title
SDL_Texture* titleText = SDL_CreateTextureFromSurface(renderer, title);
SDL_RenderCopy(renderer, titleText, NULL, &titleRect);
//text for login screen
if (strcmp(screenType,"login")==0){
char* promptBuf=prompt;
SDL_Surface* psurface = TTF_RenderText_Solid(Sans, promptBuf, black);//prompt
SDL_Texture* ptext = SDL_CreateTextureFromSurface(renderer, psurface);
SDL_RenderCopy(renderer, ptext, NULL, &promptBox);
char* inputBuf=input;
SDL_Surface* isurface = TTF_RenderText_Solid(Sans, inputBuf, black);//prompt
SDL_Texture* itext = SDL_CreateTextureFromSurface(renderer, isurface);
//fixing the text resize bug
SDL_Rect loginInputT;
loginInputT.x=loginInput.x;
loginInputT.y=loginInput.y;
loginInputT.w=loginInput.w;
loginInputT.h=loginInput.h;
TTF_SetFontSize(Sans, 70);
if (strlen(inputBuf)!=0) {
loginInputT.w=isurface->w;
loginInputT.h=isurface->h;
if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")!=0) {
loginInput.w=isurface->w;
loginInput.h=isurface->h;
} else {
loginInput.w=70;
loginInput.h=70;
}
loginInput.x=loginSquare.x+loginSquare.w/2 -loginInput.w/2;
loginInput.y=loginSquare.h-loginInput.h/2;
}
SDL_RenderCopy(renderer, itext, NULL, <oginInputT);
SDL_FreeSurface(psurface);
SDL_DestroyTexture(ptext);
SDL_FreeSurface(isurface);
SDL_DestroyTexture(itext);
}
//text for messaging screen
if (strcmp(screenType,"messaging")==0){
char* inputBuf=input;
TTF_SetFontSize(Sans, 40);
SDL_Surface* isurface = TTF_RenderText_Solid(Sans, inputBuf, black);//prompt
SDL_Texture* itext = SDL_CreateTextureFromSurface(renderer, isurface);
if (strlen(inputBuf)!=0){
sendBox.w=isurface->w;
sendBox.h=isurface->h;
} else {
sendBox.w=400;
sendBox.h=50;
}
SDL_RenderCopy(renderer, itext, NULL, &sendBox);
char* promptBuf=prompt;
SDL_Surface* psurface = TTF_RenderText_Solid(Sans, promptBuf, black);//prompt
SDL_Texture* ptext = SDL_CreateTextureFromSurface(renderer, psurface);
SDL_RenderCopy(renderer, ptext, NULL, &personBox);
char* labelText="last message received";
SDL_Surface* lsurface = TTF_RenderText_Solid(Sans, labelText, black);//prompt
SDL_Texture* ltext = SDL_CreateTextureFromSurface(renderer, lsurface);
SDL_RenderCopy(renderer, ltext, NULL, <abel);
char* lastText=lastMessage;
TTF_SetFontSize(Sans, 40-strlen(lastMessage)/30);
SDL_Surface* ltsurface = TTF_RenderText_Solid(Sans, lastText, black);//prompt
SDL_Texture* lttext = SDL_CreateTextureFromSurface(renderer, ltsurface);
if (strlen(lastMessage)!=0){
m1.w=ltsurface->w;
m1.h=ltsurface->h;
m1.x=width/2-m1.w/2;
m1.y=height/2-m1.h/2+label.h;
}
TTF_SetFontSize(Sans, 70);
SDL_RenderCopy(renderer, lttext, NULL, &m1);
SDL_FreeSurface(isurface);
SDL_DestroyTexture(itext);
SDL_FreeSurface(psurface);
SDL_DestroyTexture(ptext);
SDL_FreeSurface(lsurface);
SDL_DestroyTexture(ltext);
SDL_FreeSurface(ltsurface);
SDL_DestroyTexture(lttext);
}
for (int i=0;i<6;i++) drawCircle(renderer,squares[i].x+squares[i].w/2,squares[0].y+squares[0].h/2,30);
SDL_RenderPresent(renderer);
// Don't forget to free your surface and texture
SDL_FreeSurface(title);
SDL_DestroyTexture(titleText);
SDL_DestroyTexture(texture);
if (strcmp(prompt,"Wrong login")==0||strcmp(prompt,"account created")==0){
SDL_Delay(500);
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"do you have an account? Enter Y for yes, or N for no");
promptBox.w=10*strlen(prompt);
memset(input,sizeof(input),0);
strcpy(input,"");
}
if (strcmp(prompt,"You're logged in!")==0) {
SDL_Delay(500);
memset(screenType,0,sizeof(screenType));
strcpy(screenType,"messaging");
memset(prompt,sizeof(prompt),0);
strcpy(prompt,"enter the message you want to send");
bottombar.y-=50;
bottombar.h+=50;
sendBox.y-=50;
sendBox.h-=200;
}
}
//cleanup
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
IMG_Quit();
SDL_Quit();
shutdown(ConnectSocket, SD_SEND);
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
This is the client side of the messaging app, again, written entirely in C. The client functions by connecting to the server (obviously the server and client are binded to the right IP, although this would vary if you tried running this at home) and then allowing you to login. The GUI was made using SDL2. Getting the client and server side to sync up along with the GUI was a massively fun (even if nightmarish) process, but I enjoyed it and I always try to think of ways to modify and improve this code, below is an example of 2 of the clients communicating with each other
#include <iostream>
#include <memory>
#include <Windows.h>
#include <process.h>
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
const int width=1024,height=576;//screen proportions
const double gravity=0.7;//gravity
bool end=false;//value to see if the game ended
struct spriteTemplate {//sprite struct
std::string imageSrc;
std::string backwardsImg;
int framesMax;
int framesHold;
struct {
int height;
int width;
} scales;
int offset;
};
struct character {//character struct
double position[2];
double velocity[2];
struct {
int x;
int y;
int width;
int height;
int knockback;
int frame;
} attackStats;
std::string imageSrc;
int framesMax;
int framesHold;
int framesElapsed;
int currentFrame=1;
struct {
spriteTemplate idle;
spriteTemplate run;
spriteTemplate jump;
spriteTemplate fall;
spriteTemplate attack1;
spriteTemplate takeHit;
spriteTemplate death;
} sprites;
int height;
int width;
int speed;
int jumpH;
int offset;
};
character Richard {
{400,100},//position
{0,0},//velocity
{
50,//x
67,//y
200,//width
100,//height
30,//knockback
3//frame
},//attackStats
"richardIdle.png",//imgSrc
8,//framesMax
6,//framesHold
0,//framesElapsed
1,//currentFrame
{//sprites struct
{
"richardIdle.png",
"richardIdlebackwards.png",
8,
6,
{
200,
250
},
16
},
{
"richardRun.png",
"richardRunbackwards.png",
7,
9,
{
200,
250
},
0
},
{
"richardJump.png",
"richardJumpbackwards.png",
2,
12,
{
230,
260
},
20
},
{
"richardFall.png",
"richardFallbackwards.png",
2,
5,
{
200,
250
},
30
},
{
"richardAttack1.png",
"richardAttack1backwards.png",
5,
8,
{
200,
250
},
0
},
{
"richardTake hit.png",
"richardTake hitbackwards.png",
5,
4,
{
200,
250
},
23
},
{
"richardDeath.png",
"richardDeathbackwards.png",
9,
6,
{
200,
250
},
0
}
},
200,//height
250,//width
3,//speed
13,//jump height
16//offset
};
character Dracaena {
{0,100},//position
{0,0},//velocity
{
90,//x
38,//y
93,//width
58,//height
20,//knockback
3//frame
},//attackStats
"dracIdle.png",//imgSrc
4,//framesMax
15,//framesHold
0,//framesElapsed
1,//currentFrame
{//sprites struct
{
"dracIdle.png",
"dracIdlebackwards.png",
4,
15,
{
170,
180
},
70
},
{
"dracRun.png",
"dracRunbackwards.png",
11,
7,
{
170,
210
},
15
},
{
"dracJump.png",
"dracJumpbackwards.png",
3,
7,
{
160,
190
},
100
},
{
"dracFall.png",
"dracFallbackwards.png",
2,
2,
{
150,
180
},
100
},
{
"dracAttack1.png",
"dracAttack1backwards.png",
4,
10,
{
170,
210
},
40
},
{
"dracTake hit.png",
"dracTake hitbackwards.png",
3,
11,
{
170,
190
},
132
},
{
"dracDeath.png",
"dracDeathbackwards.png",
10,
9,
{
170,
210
},
20
}
},
170,//height
210,//width
6,//speed
15,//jump height
106//offset
};
struct {
struct {
bool pressed=false;
} a;
struct {
bool pressed=false;
} d;
struct {
bool pressed=false;
} w;
struct {
bool pressed=false;
} ArrowLeft;
struct {
bool pressed=false;
} ArrowRight;
struct {
bool pressed=false;
} ArrowUp;
} keys;
class LTimer {
public:
//Initializes variables
LTimer();
//The various clock actions
void start();
void stop();
void pause();
void unpause();
//Gets the timer's time
Uint32 getTicks();
//Checks the status of the timer
bool isStarted();
bool isPaused();
private:
//The clock time when the timer started
Uint32 mStartTicks;
//The ticks stored when the timer was paused
Uint32 mPausedTicks;
//The timer status
bool mPaused;
bool mStarted;
};
LTimer::LTimer(){
//Initialize the variables
mStartTicks = 0;
mPausedTicks = 0;
mPaused = false;
mStarted = false;
}
void LTimer::start(){
//Start the timer
mStarted = true;
//Unpause the timer
mPaused = false;
//Get the current clock time
mStartTicks = SDL_GetTicks();
mPausedTicks = 0;
}
void LTimer::stop(){
//Stop the timer
mStarted = false;
//Unpause the timer
mPaused = false;
//Clear tick variables
mStartTicks = 0;
mPausedTicks = 0;
}
void LTimer::pause(){
//If the timer is running and isn't already paused
if( mStarted && !mPaused )
{
//Pause the timer
mPaused = true;
//Calculate the paused ticks
mPausedTicks = SDL_GetTicks() - mStartTicks;
mStartTicks = 0;
}
}
void LTimer::unpause(){
//If the timer is running and paused
if( mStarted && mPaused )
{
//Unpause the timer
mPaused = false;
//Reset the starting ticks
mStartTicks = SDL_GetTicks() - mPausedTicks;
//Reset the paused ticks
mPausedTicks = 0;
}
}
Uint32 LTimer::getTicks(){
//The actual timer time
Uint32 time = 0;
//If the timer is running
if( mStarted )
{
//If the timer is paused
if( mPaused )
{
//Return the number of ticks when the timer was paused
time = mPausedTicks;
}
else
{
//Return the current time minus the start time
time = SDL_GetTicks() - mStartTicks;
}
}
return time;
}
bool LTimer::isStarted(){
//Timer is running and paused or unpaused
return mStarted;
}
bool LTimer::isPaused(){
//Timer is running and paused
return mPaused && mStarted;
}
class fighter {
public:
SDL_Surface * sprite;
SDL_Rect og;//rectangle of og image
SDL_Rect target;//where I want to place the image
SDL_Rect attackBox;//where I want to place the image
SDL_Texture * fImage;
int framesElapsed=0;
int currentFrame=1;
int framesMax;
int framesHold;
struct character buffer;
bool dead=false;
bool isAttacking=false;
bool attackPress=true;
std::string lastKey;
int jumpArc=0;
int jumpH;
int speed;
int health=100;
SDL_Renderer * renderer;
int frameWidth;
fighter(struct character player,SDL_Renderer * renderer1){
framesMax=player.framesMax;
framesHold=player.framesHold;
buffer=player;
speed=buffer.speed;
jumpH=buffer.jumpH;
sprite = IMG_Load((player.imageSrc).c_str());//loading an image
og.x = buffer.offset;
og.y = 0;
frameWidth=(sprite->w/framesMax);
if (sprite->w%framesMax!=0) frameWidth++;
og.w = frameWidth-buffer.offset;
og.h = sprite->h;
attackBox.x = player.attackStats.x;
attackBox.y = player.attackStats.y;
attackBox.w = player.attackStats.width;
attackBox.h = player.attackStats.height;
target.x = player.position[0];
target.y = player.position[1];
target.w = og.w;
target.h = buffer.height;
renderer=renderer1;
fImage=SDL_CreateTextureFromSurface(renderer,sprite);
}
void draw(){
SDL_DestroyTexture(fImage);//memory leak prevention
target.x=buffer.position[0];
target.y=buffer.position[1];
fImage = SDL_CreateTextureFromSurface(renderer, sprite);//rendering the sprite
SDL_RenderCopy(renderer, fImage, &og, &target);//placing the sprite
}
void attack(std::string direction=""){
switchSprite(4,direction);
if (direction=="") attackBox.x=target.x+buffer.attackStats.x;
else attackBox.x=target.x+target.w-buffer.attackStats.x-buffer.attackStats.width;
attackBox.w=buffer.attackStats.width;
attackBox.y=target.y+buffer.attackStats.y;
attackBox.h=buffer.attackStats.height;
isAttacking=true;
}
void takeHit(std::string direction=""){
health-=20;
if (health<=0) switchSprite(6,direction);
else switchSprite(5,direction);
}
void animateFrames(float timeStep){
if (timeStep*100>=.6){
og.x = currentFrame * frameWidth + buffer.offset;
framesElapsed++;
if (framesElapsed%framesHold==0){
if (currentFrame<framesMax-1){
currentFrame++;
} else {
currentFrame=0;
}
}
}
}
void update(float timeStep){
draw();
if (!dead) animateFrames(timeStep);
if ((buffer.imageSrc==buffer.sprites.death.imageSrc||buffer.imageSrc==buffer.sprites.death.backwardsImg)&&buffer.position[1]==479-target.h) return;
buffer.position[1] +=buffer.velocity[1]*timeStep*100;
//border detection
if (target.x+target.w+buffer.velocity[0]>width) buffer.position[0]=width-target.w;
else if (target.x+buffer.velocity[0]<0) buffer.position[0]=0;
else buffer.position[0] +=buffer.velocity[0]*timeStep*100;
//gravity detection
if (target.y+target.h+buffer.velocity[1]>=479){
buffer.velocity[1]=0;
buffer.position[1]=479-target.h;
if (buffer.velocity[0]==0) jumpArc=0;
} else {
buffer.velocity[1]+=gravity;
}
}
void swapper(spriteTemplate currentSprite,std::string direction=""){
if (direction=="backwards") buffer.imageSrc=currentSprite.backwardsImg;
else buffer.imageSrc=currentSprite.imageSrc;
SDL_FreeSurface(sprite);
framesMax=currentSprite.framesMax;
framesHold=currentSprite.framesHold;
buffer.height=currentSprite.scales.height;
buffer.width=currentSprite.scales.width;
buffer.offset=currentSprite.offset;
target.h=buffer.height;
target.w=buffer.width;
sprite = IMG_Load((buffer.imageSrc).c_str());
og.x=currentSprite.offset;
og.y=0;
frameWidth=(sprite->w/framesMax);
if (sprite->w%framesMax!=0) frameWidth++;
og.w = frameWidth-currentSprite.offset;
og.h = sprite->h;
currentFrame=0;
framesElapsed=0;
if (target.y+target.h>=479) buffer.position[1]-=target.y+target.h-479;
}
std::string switchSprite(int pos,std::string direction=""){
if (dead) return "";
if (buffer.imageSrc==buffer.sprites.death.imageSrc||buffer.imageSrc==buffer.sprites.death.backwardsImg) {
if (currentFrame==buffer.sprites.death.framesMax-1) dead=true;
return "";
}
if ((buffer.imageSrc==buffer.sprites.takeHit.imageSrc||buffer.imageSrc==buffer.sprites.takeHit.backwardsImg)&¤tFrame<buffer.sprites.takeHit.framesMax-1) return "";
if ((buffer.imageSrc==buffer.sprites.attack1.imageSrc||buffer.imageSrc==buffer.sprites.attack1.backwardsImg)&¤tFrame==buffer.sprites.attack1.framesMax-1) isAttacking=false;
if ((buffer.imageSrc==buffer.sprites.attack1.imageSrc||buffer.imageSrc==buffer.sprites.attack1.backwardsImg)&¤tFrame<buffer.sprites.attack1.framesMax-1) return "";
switch (pos){
case 0:
if (buffer.imageSrc!=buffer.sprites.idle.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.idle.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.idle,direction);
break;
case 1:
if (buffer.imageSrc!=buffer.sprites.run.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.run.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.run,direction);
break;
case 2:
if (buffer.imageSrc!=buffer.sprites.jump.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.jump.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.jump,direction);
break;
case 3:
if (buffer.imageSrc!=buffer.sprites.fall.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.fall.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.fall,direction);
break;
case 4:
if (buffer.imageSrc!=buffer.sprites.attack1.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.attack1.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.attack1,direction);
break;
case 5:
if (buffer.imageSrc!=buffer.sprites.takeHit.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.takeHit.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.takeHit,direction);
break;
case 6:
if (buffer.imageSrc!=buffer.sprites.death.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.death.backwardsImg&&direction=="backwards"))
swapper(buffer.sprites.death,direction);
break;
}
return "";
}
};
bool rectangleCollision(SDL_Rect rect1,SDL_Rect rect2){
return ((rect1.x+rect1.w>=rect2.x&&rect1.x+rect1.w<=rect2.x+rect2.w)||(rect1.x>=rect2.x&&rect1.x<=rect2.x+rect2.w))&&((rect1.y+rect1.h>=rect2.y&&rect1.y+rect1.h<=rect2.y+rect2.h)||(rect1.y>=rect2.y&&rect1.y<=rect2.y+rect2.h));
}
int timerValue=60;
unsigned __stdcall decreaseTimer(void * data){
int *tptr=&timerValue;
if (*tptr>0&&!end){
SDL_Delay(1000);
*tptr=timerValue-1;
decreaseTimer(data);
}
return 0;
}
int main(int argc,char *argv[]){
bool quit = false;
SDL_Event event;
//initializing everything
SDL_Init( SDL_INIT_EVERYTHING );
IMG_Init(IMG_INIT_PNG);
IMG_Init(IMG_INIT_JPG);
TTF_Init();
SDL_Window * window = SDL_CreateWindow("Fighting Game",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);//creating a window
SDL_Surface * icon=IMG_Load("penisforeskinicon.JPG");//the tab icon
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);//creating the renderer
SDL_Texture * texture;//rendering the background
SDL_Rect container;//the container for health bars and timer
TTF_Font* Sans = TTF_OpenFont("The Wild Breath of Zelda.otf", 24);//the font
SDL_Color White = {255, 255, 255};
std::string screen="menu";//the string that stores the current screen
SDL_Rect playButton;//menu rect
playButton.x=80;
playButton.w=200;
playButton.y=100;
playButton.h=100;
SDL_Rect credit;
credit.x=80;
credit.w=900;
credit.y=playButton.y+playButton.h+20;
credit.h=120;
//select screen rects and select screen stuff
SDL_Surface *portraits[2]={IMG_Load("dracPortrait.PNG"),IMG_Load("richardPortrait.PNG")};
SDL_Texture *portraitTextures[2]={SDL_CreateTextureFromSurface(renderer, portraits[0]),SDL_CreateTextureFromSurface(renderer, portraits[1])};
SDL_Rect backButton;
backButton.x=80;
backButton.w=140;
backButton.y=50;
backButton.h=100;
SDL_Rect characterBox[2];
characterBox[0].x=405;
characterBox[0].y=205;
characterBox[0].w=50;
characterBox[0].h=50;
SDL_Rect characters[2];
characters[0].x=400;
characters[0].y=200;
characters[0].w=60;
characters[0].h=60;
for (int i=1,x=0;i<2;i++,x+=10){
characters[i].x=characters[i-1].x+characters[i-1].w+10;
characters[i].y=200;
characters[i].w=60;
characters[i].h=60;
characterBox[i].x=characters[i-1].x+characters[i-1].w+15;
characterBox[i].y=205;
characterBox[i].w=50;
characterBox[i].h=50;
}
//setting the container properties
container.w=800;
container.h=60;
container.x=(width/2)-(container.w/2);
container.y=10;
//the invidual healthbar and timer stuff
SDL_Rect healthBar1;
SDL_Rect healthBar2;
SDL_Rect healthBarBack1;
SDL_Rect healthBarBack2;
SDL_Rect timer;
healthBarBack1.w=360;
healthBarBack1.x=container.x+5;
healthBarBack1.y=container.y+5;
healthBarBack1.h=50;
healthBarBack2.w=360;
healthBarBack2.x=container.x+5+healthBarBack1.w+70;
healthBarBack2.y=container.y+5;
healthBarBack2.h=50;
healthBar1.w=355;
healthBar1.x=healthBarBack1.x+5;
healthBar1.y=healthBarBack1.y+5;
healthBar1.h=40;
healthBar2.w=355;
healthBar2.x=container.x+5+healthBarBack1.w+70;
healthBar2.y=healthBarBack2.y+5;
healthBar2.h=40;
timer.w=70;
timer.h=60;
timer.x=container.x+5+healthBarBack1.w;
timer.y=container.y;
SDL_Rect endMessage; //create a rect
endMessage.x = width/2 - 300/2; //controls the rect's x coordinate
endMessage.y = height/2 - 300/2; // controls the rect's y coordinte
endMessage.w = 300; // controls the width of the rect
endMessage.h = 300; // controls the height of the rect
SDL_SetWindowIcon(window, icon);//setting the window
SDL_Event windowEvent;
int xMouse=0, yMouse=0;//I have absolutely no fucking idea what I'm doing
fighter * player=NULL;//initializing the fighters, gonna redo this later so you can select your fighter
fighter *enemy=NULL;
LTimer stepTimer;
//starting the timer, gotta move this when I do the character select shit
int *tptr=&timerValue;
//the while loop for the game
while (true){
if (SDL_PollEvent(&windowEvent)){
if (SDL_QUIT==windowEvent.type){
break;
}
}
//menu screen
if (screen=="menu"){
SDL_Surface * image = IMG_Load("background.png");//loading the background image
SDL_Surface* play = TTF_RenderText_Solid(Sans, "PLAY", White);
SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, play);
SDL_Surface* credits = TTF_RenderText_Solid(Sans, "Credit to pkmarie04 and nacho_cheeze for sprites", White);
SDL_Texture* credMessage = SDL_CreateTextureFromSurface(renderer, credits);
if(windowEvent.type == SDL_MOUSEMOTION) SDL_GetMouseState(&xMouse,&yMouse);
if ((xMouse<=playButton.x+playButton.w&&xMouse>=playButton.x)&&(yMouse<=playButton.y+playButton.h&&yMouse>=playButton.y)) SDL_FillRect(image,&playButton,0xFF0000FF);
texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background
SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background
SDL_RenderCopy(renderer, Message, NULL, &playButton);
SDL_RenderCopy(renderer, credMessage, NULL, &credit);
SDL_RenderPresent(renderer);
SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly
SDL_FreeSurface(play);
SDL_DestroyTexture(Message);
SDL_FreeSurface(credits);
SDL_DestroyTexture(credMessage);
SDL_FreeSurface(image);
SDL_DestroyTexture(texture);
if(windowEvent.type == SDL_MOUSEBUTTONDOWN) {
if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=playButton.x+playButton.w&&xMouse>=playButton.x)&&(yMouse<=playButton.y+playButton.h&&yMouse>=playButton.y))) {
screen="select";
xMouse=0;
yMouse=0;
}
}
}
//select screen
if (screen=="select"){
SDL_Surface * image = IMG_Load("background.png");//loading the background image
if(windowEvent.type == SDL_MOUSEMOTION) SDL_GetMouseState(&xMouse,&yMouse);
if ((xMouse<=backButton.x+backButton.w&&xMouse>=backButton.x)&&(yMouse<=backButton.y+backButton.h&&yMouse>=backButton.y)) SDL_FillRect(image,&backButton,0xFF0000FF);
SDL_FillRects(image,characters,2,0xFFF00000);
texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background
SDL_Surface* back = TTF_RenderText_Solid(Sans, "BACK", White);
SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, back);
SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background
SDL_RenderCopy(renderer, Message, NULL, &backButton);//placing the text for the back button
for (int i=0;i<t2;i++){
SDL_RenderCopy(renderer, portraitTextures[i], NULL, &characterBox[i]);
}
SDL_RenderPresent(renderer);
SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly
SDL_FreeSurface(image);
SDL_DestroyTexture(texture);
SDL_FreeSurface(back);
SDL_DestroyTexture(Message);
if(windowEvent.type == SDL_MOUSEBUTTONDOWN) {
if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=backButton.x+backButton.w&&xMouse>=backButton.x)&&(yMouse<=backButton.y+backButton.h&&yMouse>=backButton.y))) {
screen="menu";
xMouse=0;
yMouse=0;
}
if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=characters[0].x+characters[0].w&&xMouse>=characters[0].x)&&(yMouse<=characters[0].y+characters[0].h&&yMouse>=characters[0].y))) {
if (player==NULL) player=new fighter(Dracaena,renderer);
else enemy=new fighter(Dracaena,renderer);
}
if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=characters[1].x+characters[1].w&&xMouse>=characters[1].x)&&(yMouse<=characters[1].y+characters[1].h&&yMouse>=characters[1].y))) {
if (player==NULL) player=new fighter(Richard,renderer);
else enemy=new fighter(Richard,renderer);
}
if (player!=NULL&&enemy!=NULL) {
screen="game";
unsigned threadID;
(HANDLE)_beginthreadex(NULL, 0, &decreaseTimer, (void*)tptr, 0, &threadID);
}
}
}
//the actual fighting game code
if (screen=="game"){
SDL_Surface * image = IMG_Load("background.png");//loading the background image
//this code is so they don't go infinitely in whatever direction they started in
player->buffer.velocity[0]=0;
enemy->buffer.velocity[0]=0;
switch(windowEvent.type){
case SDL_KEYDOWN:
switch (windowEvent.key.keysym.sym){
case SDLK_a:
keys.a.pressed=true;
player->lastKey='a';
break;
case SDLK_d:
keys.d.pressed=true;
player->lastKey='d';
break;
case SDLK_w:
if (player->buffer.velocity[1]==0) player->buffer.velocity[1]=-player->jumpH;
break;
case SDLK_SPACE:
if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) player->attack();
else player->attack("backwards");
player->attackPress=false;
//SDL_FillRect(image,&player->attackBox,0xFF0000FF);
break;
case SDLK_RIGHT:
keys.ArrowRight.pressed=true;
enemy->lastKey="ArrowRight";
break;
case SDLK_LEFT:
keys.ArrowLeft.pressed=true;
enemy->lastKey="ArrowLeft";
break;
case SDLK_UP:
if (enemy->buffer.velocity[1]==0){
enemy->buffer.velocity[1]=-enemy->jumpH;
}
break;
case SDLK_DOWN:
if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) enemy->attack();
else enemy->attack("backwards");
enemy->attackPress=false;
//SDL_FillRect(image,&enemy->attackBox,0xFF0000FF);
break;
}
break;
case SDL_KEYUP:
switch (windowEvent.key.keysym.sym){
case SDLK_a:
keys.a.pressed=false;
break;
case SDLK_d:
keys.d.pressed=false;
break;
case SDLK_SPACE:
player->attackPress=true;
break;
case SDLK_RIGHT:
keys.ArrowRight.pressed=false;
break;
case SDLK_LEFT:
keys.ArrowLeft.pressed=false;
break;
case SDLK_DOWN:
enemy->attackPress=true;
break;
}
break;
}
//player movement
if (keys.a.pressed&&player->lastKey=="a"&&player->buffer.imageSrc!=player->buffer.sprites.takeHit.imageSrc&&player->buffer.velocity[1]==0) {
player->buffer.velocity[0]=-player->speed;
player->jumpArc=-player->speed;
player->switchSprite(1,"backwards");
} else if (keys.d.pressed&&player->lastKey=="d"&&player->buffer.imageSrc!=player->buffer.sprites.takeHit.imageSrc&&player->buffer.velocity[1]==0) {
player->buffer.velocity[0]=player->speed;
player->jumpArc=player->speed;
player->switchSprite(1);
}
if (player->buffer.velocity[1]<0){
if (player->jumpArc!=0) player->buffer.velocity[0]=player->jumpArc;
if ((enemy->target.x+enemy->target.w>player->target.x+player->target.w&&player->buffer.velocity[0]==0)||player->buffer.velocity[0]>0) player->switchSprite(2);
else player->switchSprite(2,"backwards");
} else if (player->buffer.velocity[1]>0){
if (player->jumpArc!=0) player->buffer.velocity[0]=player->jumpArc;
if ((enemy->target.x+enemy->target.w>player->target.x+player->target.w&&player->buffer.velocity[0]==0)||player->buffer.velocity[0]>0) player->switchSprite(3);
else player->switchSprite(3,"backwards");
} else if (player->buffer.velocity[0]==0&&player->buffer.velocity[1]==0){
if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) player->switchSprite(0);
else player->switchSprite(0,"backwards");
}
//enemy movement
if (keys.ArrowLeft.pressed&&enemy->lastKey=="ArrowLeft"&&enemy->buffer.imageSrc!=enemy->buffer.sprites.takeHit.imageSrc&&enemy->buffer.velocity[1]==0) {
enemy->buffer.velocity[0]=-enemy->speed;
enemy->jumpArc=-enemy->speed;
enemy->switchSprite(1,"backwards");
} else if (keys.ArrowRight.pressed&&enemy->lastKey=="ArrowRight"&&enemy->buffer.imageSrc!=enemy->buffer.sprites.takeHit.imageSrc&&enemy->buffer.velocity[1]==0) {
enemy->buffer.velocity[0]=enemy->speed;
enemy->jumpArc=enemy->speed;
if (enemy->buffer.velocity[1]==0){
enemy->switchSprite(1);
}
}
if (enemy->buffer.velocity[1]<0){
if (enemy->jumpArc!=0) enemy->buffer.velocity[0]=enemy->jumpArc;
if ((player->target.x+player->target.w>enemy->target.x+enemy->target.w&&enemy->buffer.velocity[0]==0)||enemy->buffer.velocity[0]>0) enemy->switchSprite(2);
else enemy->switchSprite(2,"backwards");
} else if (enemy->buffer.velocity[1]>0){
if (enemy->jumpArc!=0) enemy->buffer.velocity[0]=enemy->jumpArc;
if ((player->target.x+player->target.w>enemy->target.x+enemy->target.w&&enemy->buffer.velocity[0]==0)||enemy->buffer.velocity[0]>0) enemy->switchSprite(3);
else enemy->switchSprite(3,"backwards");
} else if (enemy->buffer.velocity[0]==0&&enemy->buffer.velocity[1]==0){
if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) enemy->switchSprite(0);
else enemy->switchSprite(0,"backwards");
}
//collision detection and hitting
if (rectangleCollision(player->attackBox,enemy->target)&&player->isAttacking&&player->currentFrame==player->buffer.attackStats.frame-1) {
if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) enemy->takeHit("backwards");
else enemy->takeHit();
player->isAttacking=false;
healthBar2.w-=71;
}
if (rectangleCollision(enemy->attackBox,player->target)&&enemy->isAttacking&&enemy->currentFrame==enemy->buffer.attackStats.frame-1) {
if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) player->takeHit("backwards");
else player->takeHit();
enemy->isAttacking=false;
healthBar1.x+=71;
healthBar1.w-=71;
}
//the ui display stuff
SDL_FillRect(image,&healthBarBack1,0);
SDL_FillRect(image,&healthBarBack2,0);
SDL_FillRect(image,&timer,0xFF0000FF);
SDL_FillRect(image,&healthBar1,0xFFF00000);
SDL_FillRect(image,&healthBar2,0xFFF00000);
//SDL_FillRect(image,&player->target,0xFF0000FF);//hitbox tracking temporary remove later
//SDL_FillRect(image,&enemy->target,0xFF0000FF);//hitbox tracking temporary remove later
texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background
SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background
//timer display shit
SDL_Surface* timerNum = TTF_RenderText_Solid(Sans, std::to_string(timerValue).c_str(), White);
SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, timerNum);
SDL_RenderCopy(renderer, Message, NULL, &timer);
//frame rate independence shit
float timeStep=stepTimer.getTicks()/1000.f;
//updating the fighters
player->update(timeStep);
enemy->update(timeStep);
//Restart step timer
stepTimer.start();
SDL_RenderPresent(renderer);
SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly
SDL_FreeSurface(image);
SDL_DestroyTexture(texture);
SDL_FreeSurface(timerNum);
SDL_DestroyTexture(Message);
//finishing the game stuff
if (player->health<=0||enemy->health<=0||timerValue==0){
if ((player->buffer.imageSrc==player->buffer.sprites.death.imageSrc||player->buffer.imageSrc==player->buffer.sprites.death.backwardsImg)&&player->currentFrame==player->buffer.sprites.death.framesMax-1){
delete player;
delete enemy;
player=NULL;
enemy=NULL;
*tptr=60;
healthBar1.w=355;
healthBar1.x=healthBarBack1.x+5;
healthBar1.y=healthBarBack1.y+5;
healthBar1.h=40;
healthBar2.w=355;
healthBar2.x=container.x+5+healthBarBack1.w+70;
healthBar2.y=healthBarBack2.y+5;
healthBar2.h=40;
SDL_Delay(1500);
screen = "select";
} else if ((enemy->buffer.imageSrc==enemy->buffer.sprites.death.imageSrc||enemy->buffer.imageSrc==enemy->buffer.sprites.death.backwardsImg)&&enemy->currentFrame==enemy->buffer.sprites.death.framesMax-1){
delete player;
delete enemy;
player=NULL;
enemy=NULL;
*tptr=60;
healthBar1.w=355;
healthBar1.x=healthBarBack1.x+5;
healthBar1.y=healthBarBack1.y+5;
healthBar1.h=40;
healthBar2.w=355;
healthBar2.x=container.x+5+healthBarBack1.w+70;
healthBar2.y=healthBarBack2.y+5;
healthBar2.h=40;
SDL_Delay(1500);
screen = "select";
}
}
}
}
//cleanup
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}
This is the code for the fighting game, although this was written in C++, the JavaScript version is playable on the "Games" tab. This was written in C++ with SDL2 It's basically the same as the one on the "Games" tab, however to give you the rundown, it has its own animation system, a proper timer, character select, and all the basic mechanisms behind fighting games. This was fun to make as I had to work with my friends to implement the sprite work and characters. Some days I muse on improving on it and publishing it as a full-fledged game, but that's perhaps for another time
#include <LiquidCrystal.h>
String buffer="";
String evaluate(String eq,int start, int end){
int index=0;
String ptr[100];
String buffer="";
double answer=0;
for (int i=0;i<eq.length();i++){
if (eq[i]!='+'&&eq[i]!='-'&&eq[i]!='*'&&eq[i]!='/') {
if (buffer[buffer.length()-1]=='.'&&eq[i]=='.') return "Syntax Error";
buffer+=eq[i];
} else {
ptr[index]=buffer;
index++;
String s(eq[i]);
ptr[index]=s;
index++;
buffer="";
}
}
ptr[index]=buffer;
index++;
String nextPos="";
String swapper=ptr[0];
if (ptr[0]!="-") {
for (int k = index; k > 0; k--){
ptr[k]=ptr[k-1];
}
ptr[0]="+";
index++;
}
for (int i=0;i<index;i++){
if (ptr[i]=="/"||ptr[i]=="*"){
String temp;
if (ptr[i]=="/") temp=String(ptr[i-1].toFloat()/ptr[i+1].toFloat());
else temp=String(ptr[i-1].toFloat()*ptr[i+1].toFloat());
for(int k = i+1,c=i; k < index; k++,c++) ptr[c] = ptr[k];
index--;
for(int k = i+1,c=i; k < index; k++,c++) ptr[c] = ptr[k];
index--;
ptr[i-1]=temp;
i--;
}
}
for (int i=0;i<index;i++){
if (ptr[i]=="+"||ptr[i]=="-"){
if (ptr[i]=="+") answer+=ptr[i+1].toFloat();
else answer-=ptr[i+1].toFloat();
i++;
}
}
return String(answer);
}
bool test(int pin){
if (digitalRead(pin)==HIGH) return true;
return false;
}
LiquidCrystal lcd(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
void setup() {
lcd.begin(16, 2);
}
bool activate=false;
void loop() {
if (test(2)&&!test(3)&&!test(4)&&!test(5)) {
buffer+=String('1');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&test(3)&&!test(4)&&!test(5)) {
buffer+=String('2');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&test(3)&&!test(4)&&!test(5)) {
buffer+=String('3');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&!test(3)&&test(4)&&!test(5)) {
buffer+=String('4');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&!test(3)&&test(4)&&!test(5)) {
buffer+=String('5');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&test(3)&&test(4)&&!test(5)) {
buffer+=String('6');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&test(3)&&test(4)&&!test(5)) {
buffer+=String('7');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&!test(3)&&!test(4)&&test(5)) {
buffer+=String('8');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&!test(3)&&!test(4)&&test(5)) {
buffer+=String('9');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&test(3)&&!test(4)&&test(5)) {
buffer+=String('0');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&test(3)&&!test(4)&&test(5)) {
buffer+=String('+');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&!test(3)&&test(4)&&test(5)) {
buffer+=String('-');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&!test(3)&&test(4)&&test(5)) {
buffer+=String('*');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (!test(2)&&test(3)&&test(4)&&test(5)) {
buffer+=String('/');
delay(160);
lcd.clear();
lcd.print(buffer);
}
if (test(2)&&test(3)&&test(4)&&test(5)&&buffer!="") {
activate=true;
}
if (activate&&buffer!="") {
String temp=evaluate(buffer,0,buffer.length());
activate=false;
buffer="";
delay(160);
lcd.setCursor(0, 2);
lcd.print(temp);
}
}
This is a calculator I made using arduino. Yes a physical calculator I built. I used diodes to make a binary input system to save pin space. This is more of a foray into hardware and more hardware based projects. Below is a photo of the calculator working, I was pretty proud of myself when it all came together even though a calculator has technically been done before