2022-05-05 18:45:27 +00:00
|
|
|
// gamelogic.c: Contains function definitons for dealing with the game's logic.
|
|
|
|
// Barry Kane, 2022.
|
2022-05-20 21:28:07 +00:00
|
|
|
#include <stdio.h>
|
2022-10-16 15:13:33 +00:00
|
|
|
#include <ctype.h>
|
2022-05-05 18:45:27 +00:00
|
|
|
#include <string.h>
|
2022-10-16 15:13:33 +00:00
|
|
|
#include <stdbool.h>
|
2022-10-30 12:58:39 +00:00
|
|
|
#include <pthread.h>
|
2022-12-19 23:44:16 +00:00
|
|
|
#include "queue.h"
|
2022-10-16 15:13:33 +00:00
|
|
|
#include "constants.h"
|
|
|
|
#include "gamelogic.h"
|
|
|
|
#include "playerdata.h"
|
2022-11-13 00:23:42 +00:00
|
|
|
#include "linkedlist.h"
|
2022-10-16 15:13:33 +00:00
|
|
|
#include "inputoutput.h"
|
2022-05-05 18:45:27 +00:00
|
|
|
|
|
|
|
// =======================
|
|
|
|
// -=[ Main Game Loop ]=-:
|
|
|
|
// =======================
|
|
|
|
|
|
|
|
// Thread function which runs the main game loop, given the needed parameters:
|
2022-12-21 00:49:26 +00:00
|
|
|
void * gameLogicHandler(void * parameters)
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
|
|
|
gameLogicParameters * threadParameters = parameters;
|
|
|
|
inputMessage * currentInput = NULL;
|
2023-02-13 17:23:30 +00:00
|
|
|
queue * commandQueue = createQueue();
|
2023-02-15 21:43:13 +00:00
|
|
|
while (true)
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2022-10-16 15:13:33 +00:00
|
|
|
// Evaluate remaining commands:
|
2023-02-15 21:43:13 +00:00
|
|
|
while (commandQueue->itemCount != 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
evaluateNextCommand(threadParameters, commandQueue);
|
|
|
|
}
|
2022-12-19 23:44:16 +00:00
|
|
|
|
2022-12-21 00:49:26 +00:00
|
|
|
// Wait if there is nothing to do:
|
2023-02-15 21:43:13 +00:00
|
|
|
if (threadParameters->inputQueue->itemCount == 0)
|
2022-12-21 00:49:26 +00:00
|
|
|
{
|
|
|
|
pthread_cond_wait(&threadParameters->inputQueue->condition, &threadParameters->inputQueue->mutex);
|
|
|
|
}
|
|
|
|
|
2022-05-20 21:28:07 +00:00
|
|
|
// Check for new messages and pop them off the queue:
|
2023-02-15 21:43:13 +00:00
|
|
|
if (threadParameters->inputQueue->itemCount != 0)
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
while (threadParameters->inputQueue->lock == true);
|
2022-10-16 15:13:33 +00:00
|
|
|
threadParameters->inputQueue->lock = true;
|
2022-12-19 23:44:16 +00:00
|
|
|
currentInput = peekQueue(threadParameters->inputQueue)->data.inputMessage;
|
2022-05-05 18:45:27 +00:00
|
|
|
userInputSanatize(currentInput->content->messageContent, MAX);
|
2022-05-20 21:28:07 +00:00
|
|
|
// A slash as the first character means the message is a user command:
|
2023-02-15 21:43:13 +00:00
|
|
|
if (currentInput->content->messageContent[0] == '/')
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2022-10-16 15:13:33 +00:00
|
|
|
queueMessagedCommand(commandQueue, currentInput);
|
|
|
|
}
|
2022-12-19 23:44:16 +00:00
|
|
|
|
2022-12-20 15:55:24 +00:00
|
|
|
else if (!(currentInput->sender->currentArea == getFromList(threadParameters->areaList, 0)->area) &&
|
|
|
|
currentInput->content->messageContent[0] != '\n')
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2022-12-20 15:55:24 +00:00
|
|
|
// Copy the correct name into the sender name field:
|
2022-05-05 18:45:27 +00:00
|
|
|
strncpy(currentInput->content->senderName, currentInput->sender->playerName, 32);
|
2022-12-20 15:55:24 +00:00
|
|
|
currentInput->content->senderName[31] = '\0';
|
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
if(currentInput->sender->talkingWith == NULL)
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2023-02-19 22:13:06 +00:00
|
|
|
// Allocate an array of playerInfo to store the current players in the area for the output message:
|
|
|
|
playerInfo ** recipients = calloc(PLAYERCOUNT, sizeof(playerInfo*));
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Initialize them all to NULL:
|
|
|
|
for (int index = 0; index < PLAYERCOUNT; index++)
|
|
|
|
{
|
|
|
|
recipients[index] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the players in the current area and add them to our array:
|
|
|
|
int recipientIndex = 0;
|
|
|
|
for (int playerIndex = 0; playerIndex < *threadParameters->playerCount; playerIndex++)
|
2022-05-05 18:45:27 +00:00
|
|
|
{
|
2023-02-19 22:13:06 +00:00
|
|
|
if (threadParameters->connectedPlayers[playerIndex].currentArea == currentInput->sender->currentArea)
|
|
|
|
{
|
|
|
|
recipients[recipientIndex] = &threadParameters->connectedPlayers[playerIndex];
|
|
|
|
recipientIndex++;
|
|
|
|
}
|
2022-05-05 18:45:27 +00:00
|
|
|
}
|
2023-02-19 22:13:06 +00:00
|
|
|
|
|
|
|
// Create the outputMessage for the queue:
|
|
|
|
outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex);
|
2023-02-20 23:30:41 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Push the message onto the queue:
|
|
|
|
pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the array;
|
|
|
|
free(recipients);
|
2022-05-05 18:45:27 +00:00
|
|
|
}
|
2023-02-19 22:13:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Allocate an array of one playerInfo to store the pointer to the other player in the conversation:
|
|
|
|
playerInfo ** recipients = calloc(1, (sizeof(playerInfo*)));
|
|
|
|
|
|
|
|
// Set the talkingWith player as the recipient of the message:
|
|
|
|
recipients[0] = currentInput->sender->talkingWith;
|
|
|
|
|
|
|
|
// There's only one recipient:
|
|
|
|
int recipientIndex = 1;
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Create the outputMessage for the queue:
|
|
|
|
outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Push the message onto the queue:
|
|
|
|
pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Free the array;
|
|
|
|
free(recipients);
|
|
|
|
}
|
2022-05-05 18:45:27 +00:00
|
|
|
}
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(currentInput, 0, sizeof(inputMessage));
|
2022-05-05 18:45:27 +00:00
|
|
|
currentInput = NULL;
|
|
|
|
threadParameters->inputQueue->lock = false;
|
2022-12-19 23:44:16 +00:00
|
|
|
popQueue(threadParameters->inputQueue);
|
2022-05-05 18:45:27 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-30 12:58:39 +00:00
|
|
|
pthread_exit(NULL);
|
2022-05-05 18:45:27 +00:00
|
|
|
}
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Evaluate the next commandEvent in a queue:
|
2023-02-13 17:23:30 +00:00
|
|
|
void queueMessagedCommand(queue * queue, inputMessage * messageToQueue)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
// Prepare the new commandEvent:
|
|
|
|
commandEvent * newCommand = calloc(1, sizeof(commandEvent));
|
|
|
|
newCommand->command = calloc(16, sizeof(char));
|
|
|
|
newCommand->arguments = calloc(MAX, sizeof(char));
|
|
|
|
newCommand->caller = messageToQueue->sender;
|
|
|
|
|
|
|
|
// Seperate the command from it's arguments:
|
|
|
|
strtok(messageToQueue->content->messageContent, " ");
|
2023-02-19 22:13:06 +00:00
|
|
|
|
2022-10-16 15:13:33 +00:00
|
|
|
// Copy the command and arguments to the new commandEvent:
|
2022-10-31 01:55:44 +00:00
|
|
|
memcpy(newCommand->command, &messageToQueue->content->messageContent[1], 16);
|
|
|
|
memcpy(newCommand->arguments, &messageToQueue->content->messageContent[strlen(newCommand->command) + 2],
|
2023-02-19 00:32:03 +00:00
|
|
|
MAX - (strlen(newCommand->command) + 2));
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
|
2022-10-16 15:13:33 +00:00
|
|
|
// Ensure the arguments are safe to parse, without adding newlines:
|
|
|
|
userNameSanatize(newCommand->command, 16);
|
2022-10-31 01:55:44 +00:00
|
|
|
newCommand->command[15] = '\0';
|
|
|
|
|
2022-10-16 15:13:33 +00:00
|
|
|
userNameSanatize(newCommand->arguments, MAX);
|
2022-10-31 01:55:44 +00:00
|
|
|
newCommand->arguments[MAX - 1] = '\0';
|
2023-02-19 22:13:06 +00:00
|
|
|
|
2022-10-16 15:13:33 +00:00
|
|
|
// Lowercase the command for easier comparison:
|
|
|
|
for (char * character = newCommand->command; *character; ++character)
|
|
|
|
{
|
|
|
|
*character = tolower(*character);
|
|
|
|
}
|
|
|
|
|
2023-02-13 17:23:30 +00:00
|
|
|
pushQueue(queue, newCommand, COMMAND);
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Enqueue a command to a queue:
|
|
|
|
void queueCommand(queue * queue, char * command, char * arguments, int commandLength, int argumentsLength,
|
|
|
|
playerInfo * callingPlayer)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
// Prepare the new commandEvent:
|
|
|
|
commandEvent * newCommand = calloc(1, sizeof(commandEvent));
|
|
|
|
newCommand->command = calloc(16, sizeof(char));
|
|
|
|
newCommand->arguments = calloc(MAX, sizeof(char));
|
|
|
|
newCommand->caller = callingPlayer;
|
|
|
|
|
|
|
|
// Copy the command and arguments:
|
|
|
|
strncpy(newCommand->command, command, commandLength);
|
2023-02-15 21:43:13 +00:00
|
|
|
if (argumentsLength > 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-13 17:23:30 +00:00
|
|
|
strncpy(newCommand->arguments, arguments, argumentsLength);
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-13 17:23:30 +00:00
|
|
|
// Ensure the arguments are safe to parse, without adding newlines:
|
|
|
|
userNameSanatize(newCommand->command, 16);
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-13 17:23:30 +00:00
|
|
|
pushQueue(queue, newCommand, COMMAND);
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Evaluate the next commandEvent in a queue:
|
2023-02-13 17:23:30 +00:00
|
|
|
int evaluateNextCommand(gameLogicParameters * parameters, queue * queue)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-13 17:23:30 +00:00
|
|
|
commandEvent * currentCommand = peekQueue(queue)->data.command;
|
2023-02-15 21:43:13 +00:00
|
|
|
while (queue->lock);
|
2022-10-16 15:13:33 +00:00
|
|
|
queue->lock = true;
|
2023-02-15 21:43:13 +00:00
|
|
|
if (currentCommand == NULL)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// Switch to the relevant command based on the hash:
|
2023-02-19 00:32:03 +00:00
|
|
|
switch (hashCommand(currentCommand->command, strlen(currentCommand->command)))
|
|
|
|
{
|
|
|
|
// Look command: Returns the description of the current area and paths:
|
|
|
|
case 5626697:
|
|
|
|
{
|
|
|
|
char formattedString[64];
|
|
|
|
userMessage * lookMessage = calloc(1, sizeof(userMessage));
|
|
|
|
lookMessage->senderName[0] = '\0';
|
|
|
|
strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaName, 33);
|
|
|
|
strncat(lookMessage->messageContent, "\n", 2);
|
|
|
|
strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaDescription, MAX - 35);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
//queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1);
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(lookMessage, 0, sizeof(userMessage));
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Loop through the paths and send the appropriate amount of messages:
|
|
|
|
int charCount = 13;
|
|
|
|
strncat(lookMessage->messageContent, "You can go:", 13);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
if (currentCommand->caller->currentArea->pathList->itemCount > 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
for(size_t index = 0; index < currentCommand->caller->currentArea->pathList->itemCount; index++)
|
|
|
|
{
|
|
|
|
if ((charCount + 64) >= MAX)
|
|
|
|
{
|
|
|
|
lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(lookMessage, 0, sizeof(userMessage));
|
2023-02-19 00:32:03 +00:00
|
|
|
charCount = 0;
|
|
|
|
}
|
|
|
|
snprintf(formattedString, 64, "\n\t%ld. %s", index + 1,
|
|
|
|
getFromList(currentCommand->caller->currentArea->pathList, index)->path->pathName);
|
|
|
|
strncat(lookMessage->messageContent, formattedString, 64);
|
|
|
|
charCount += 64;
|
|
|
|
}
|
|
|
|
// Allocate another outputMessage for the queue:
|
|
|
|
lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
}
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-27 16:35:32 +00:00
|
|
|
// Clear the message:
|
|
|
|
memset(lookMessage, 0, sizeof(userMessage));
|
|
|
|
if(currentCommand->caller->currentArea != getFromList(parameters->areaList, 0)->area)
|
|
|
|
{
|
|
|
|
// Show the players in the area:
|
|
|
|
charCount = 23;
|
|
|
|
strncat(lookMessage->messageContent, "These players are here:", 24);
|
|
|
|
|
|
|
|
int playerNumber = 1;
|
|
|
|
for(int index = 0; index < *(parameters->playerCount); index++)
|
|
|
|
{
|
|
|
|
if (parameters->connectedPlayers[index].currentArea == currentCommand->caller->currentArea)
|
|
|
|
{
|
|
|
|
if ((charCount + 38) >= MAX)
|
|
|
|
{
|
|
|
|
lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
memset(lookMessage, 0, sizeof(userMessage));
|
|
|
|
charCount = 0;
|
|
|
|
}
|
|
|
|
snprintf(formattedString, 38, "\n%02d. %32s", playerNumber++,
|
|
|
|
parameters->connectedPlayers[index].playerName);
|
|
|
|
strncat(lookMessage->messageContent, formattedString, 37);
|
|
|
|
charCount += 38;
|
|
|
|
|
|
|
|
// Allocate another outputMessage for the queue:
|
|
|
|
lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(lookMessage);
|
2023-02-19 00:32:03 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stat command: Displays the current character's sheet.
|
|
|
|
case 5987604:
|
|
|
|
{
|
|
|
|
char * formattedString = calloc(121, sizeof(char));
|
|
|
|
userMessage * statMessage = calloc(1, sizeof(userMessage));
|
|
|
|
statMessage->senderName[0] = '\0';
|
|
|
|
// Basic status: Name, level, location.
|
|
|
|
snprintf(formattedString, 120, "%s, Level %d | %s\n", currentCommand->caller->playerName,
|
|
|
|
currentCommand->caller->stats->level, currentCommand->caller->currentArea->areaName);
|
|
|
|
strncat(statMessage->messageContent, formattedString, 120);
|
|
|
|
|
|
|
|
// Current stats: Health and WISED.
|
|
|
|
snprintf(formattedString, 120,
|
|
|
|
"Health: %d/%d\nStats:\n\tWits: %2d | Intellect: %2d | Strength: %2d | Endurance: %2d | Dexerity: %2d \n",
|
|
|
|
currentCommand->caller->stats->currentHealth, currentCommand->caller->stats->maxHealth,
|
|
|
|
currentCommand->caller->stats->wits, currentCommand->caller->stats->intellect,
|
|
|
|
currentCommand->caller->stats->strength, currentCommand->caller->stats->endurance,
|
|
|
|
currentCommand->caller->stats->dexerity);
|
|
|
|
strncat(statMessage->messageContent, formattedString, 120);
|
|
|
|
|
|
|
|
// Levelling stats: Current XP, and spec points.
|
|
|
|
if (currentCommand->caller->stats->specPoints > 0 || currentCommand->caller->stats->skillPoints > 0)
|
|
|
|
{
|
|
|
|
snprintf(formattedString, 120, "Current Experience: %ld | Spec Points Available: %d | Skill Points Available: %d",
|
|
|
|
currentCommand->caller->stats->experience, currentCommand->caller->stats->specPoints, currentCommand->caller->stats->skillPoints);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snprintf(formattedString, 120, "Current Experience: %ld", currentCommand->caller->stats->experience);
|
|
|
|
}
|
|
|
|
strncat(statMessage->messageContent, formattedString, 120);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
|
2022-11-13 00:23:42 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
|
2022-11-13 00:23:42 +00:00
|
|
|
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(statMessage->messageContent, 0, sizeof(char) * MAX);
|
2023-02-19 00:32:03 +00:00
|
|
|
if (currentCommand->caller->skills->head != NULL)
|
|
|
|
{
|
|
|
|
size_t skillIndex = 0;
|
|
|
|
int charCount = 0;
|
|
|
|
bool addNewline = false;
|
|
|
|
playerSkill * skill;
|
|
|
|
while (skillIndex < currentCommand->caller->skills->itemCount)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
skill = getFromList(currentCommand->caller->skills, skillIndex)->skill;
|
|
|
|
skillIndex++;
|
|
|
|
snprintf(formattedString, 120, "| %2d | %31s ", skill->skillPoints, skill->skillName);
|
|
|
|
charCount += 43;
|
|
|
|
strncat(statMessage->messageContent, formattedString, 120);
|
|
|
|
if ((charCount + 43) >= MAX)
|
|
|
|
{
|
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(statMessage, 0, sizeof(userMessage));
|
2023-02-19 00:32:03 +00:00
|
|
|
charCount = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (addNewline)
|
|
|
|
{
|
|
|
|
strncat(statMessage->messageContent, "|\n", 3);
|
|
|
|
charCount++;
|
|
|
|
addNewline = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
addNewline = true;
|
|
|
|
}
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
}
|
|
|
|
free(statMessage);
|
|
|
|
free(formattedString);
|
|
|
|
|
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
|
|
|
|
// Spec command: Assign spec points to stats:
|
|
|
|
case 5982259:
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
userMessage * specMessage = calloc(1, sizeof(userMessage));
|
|
|
|
specMessage->senderName[0] = '\0';
|
|
|
|
char * formattedString = calloc(121, sizeof(char));
|
|
|
|
if (currentCommand->caller->stats->specPoints > 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
int selectedAmount = 0;
|
|
|
|
strtok(currentCommand->arguments, " ");
|
|
|
|
selectedAmount = atoi(¤tCommand->arguments[strlen(currentCommand->arguments) + 1]);
|
|
|
|
coreStat selectedStat = getCoreStatFromString(currentCommand->arguments, 16);
|
|
|
|
if (selectedAmount > 0 && (currentCommand->caller->stats->specPoints - selectedAmount) >= 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
switch (selectedStat)
|
|
|
|
{
|
|
|
|
case WITS:
|
|
|
|
{
|
|
|
|
currentCommand->caller->stats->wits += selectedAmount;
|
|
|
|
strncat(specMessage->messageContent, "Increased wits.", 16);
|
|
|
|
currentCommand->caller->stats->specPoints -= selectedAmount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case INTELLECT:
|
|
|
|
{
|
|
|
|
currentCommand->caller->stats->intellect += selectedAmount;
|
|
|
|
strncat(specMessage->messageContent, "Increased intellect.", 21);
|
|
|
|
currentCommand->caller->stats->specPoints -= selectedAmount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case STRENGTH:
|
|
|
|
{
|
|
|
|
currentCommand->caller->stats->strength += selectedAmount;
|
|
|
|
strncat(specMessage->messageContent, "Increased strength.", 20);
|
|
|
|
currentCommand->caller->stats->specPoints -= selectedAmount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ENDURANCE:
|
|
|
|
{
|
|
|
|
currentCommand->caller->stats->endurance += selectedAmount;
|
|
|
|
strncat(specMessage->messageContent, "Increased endurance.", 21);
|
|
|
|
currentCommand->caller->stats->specPoints -= selectedAmount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DEXERITY:
|
|
|
|
{
|
|
|
|
currentCommand->caller->stats->dexerity += selectedAmount;
|
|
|
|
strncat(specMessage->messageContent, "Increased dexerity.", 21);
|
|
|
|
currentCommand->caller->stats->specPoints -= selectedAmount;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case INVALID:
|
|
|
|
{
|
|
|
|
strncat(specMessage->messageContent, "Invalid stat.", 21);
|
|
|
|
}
|
|
|
|
}
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
else
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
strncat(specMessage->messageContent, "You have entered an invalid amount of spec points.", 51);
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
else
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
strncat(specMessage->messageContent, "You have no spec points available.", 35);
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
|
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * specOutputMessage = createTargetedOutputMessage(specMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, specOutputMessage, OUTPUT_MESSAGE);
|
2023-02-16 23:08:18 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Show the new stat sheet:
|
|
|
|
queue->lock = false;
|
|
|
|
queueCommand(queue, "stat", "", 5, 0, currentCommand->caller);
|
|
|
|
queue->lock = true;
|
2023-02-16 23:08:18 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Free the finished message:
|
|
|
|
free(specMessage);
|
|
|
|
free(formattedString);
|
2023-02-16 23:08:18 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try command: Attempt to use a stat or skill on an object:
|
|
|
|
case 163143:
|
|
|
|
{
|
|
|
|
// Allocate the userMessage to send:
|
2023-02-19 22:13:06 +00:00
|
|
|
userMessage * tryMessage = calloc(1, (sizeof(userMessage)));
|
2023-02-19 00:32:03 +00:00
|
|
|
tryMessage->senderName[0] = '\0';
|
2023-02-16 23:08:18 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Temporary message until we can implement objects, events, and challenges.
|
|
|
|
strcpy(tryMessage->messageContent, "The try command is currently not implemented. Implement it if you want to use it.\n");
|
|
|
|
|
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * tryOutputMessage = createTargetedOutputMessage(tryMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, tryOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the userMessage:
|
|
|
|
free(tryMessage);
|
|
|
|
|
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
|
|
|
|
// Move command: Moves the caller to a different area given a path name or number:
|
|
|
|
case 5677603:
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
char requestedPath[32];
|
|
|
|
if (strlen(currentCommand->arguments) > 0 && currentCommand->caller->currentArea != getFromList(parameters->areaList, 0)->area)
|
|
|
|
{
|
|
|
|
memcpy(requestedPath, currentCommand->arguments, 32);
|
|
|
|
userNameSanatize(requestedPath, 32);
|
|
|
|
requestedPath[31] = '\0';
|
|
|
|
if (movePlayerToArea(currentCommand->caller, requestedPath) == 0)
|
|
|
|
{
|
|
|
|
// Call the look command after moving. It's fine to unlock, because the loop won't
|
|
|
|
// continue until the command is queued:
|
|
|
|
queue->lock = false;
|
|
|
|
queueCommand(queue, "look", "", 5, 0, currentCommand->caller);
|
|
|
|
queue->lock = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Skill command: Allows you to put skill points into skills:
|
|
|
|
case 221096235:
|
|
|
|
{
|
|
|
|
userMessage * skillMessage = calloc(1, sizeof(userMessage));
|
|
|
|
skillMessage->senderName[0] = '\0';
|
|
|
|
if ((currentCommand->caller->stats->skillPoints - 1) >= 0)
|
|
|
|
{
|
|
|
|
int returnValue = takeSkill(parameters->globalSkillList, currentCommand->arguments,
|
|
|
|
strlen(currentCommand->arguments), currentCommand->caller);
|
|
|
|
switch(returnValue)
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
{
|
|
|
|
strcpy(skillMessage->messageContent, "Not a valid skill.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
strcpy(skillMessage->messageContent, "Took ");
|
|
|
|
strcat(skillMessage->messageContent, currentCommand->arguments);
|
|
|
|
strcat(skillMessage->messageContent, ".");
|
|
|
|
currentCommand->caller->stats->skillPoints--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(skillMessage->messageContent, "You don't have enough skill points to take this skill.\n");
|
|
|
|
}
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * skillOutputMessage = createTargetedOutputMessage(skillMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, skillOutputMessage, OUTPUT_MESSAGE);
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
free(skillMessage);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Listskills commands: List all available skills on the server:
|
|
|
|
case 2395990522:
|
|
|
|
{
|
|
|
|
userMessage * listMessage = calloc(1, sizeof(userMessage));
|
|
|
|
char * formattedString = calloc(121, sizeof(char));
|
2022-10-16 15:13:33 +00:00
|
|
|
int charCount = 0;
|
2023-02-19 00:32:03 +00:00
|
|
|
size_t skillIndex = 0;
|
2022-10-16 15:13:33 +00:00
|
|
|
bool addNewline = false;
|
2023-02-19 00:32:03 +00:00
|
|
|
playerSkill * currentSkill;
|
|
|
|
while (skillIndex < parameters->globalSkillList->itemCount)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
currentSkill = getFromList(parameters->globalSkillList, skillIndex)->skill;
|
|
|
|
snprintf(formattedString, 120, "| %-31s ", currentSkill->skillName);
|
2022-10-16 15:13:33 +00:00
|
|
|
charCount += 43;
|
2023-02-19 00:32:03 +00:00
|
|
|
strncat(listMessage->messageContent, formattedString, 120);
|
|
|
|
if ((charCount + 46) >= MAX)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2022-12-20 15:55:24 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
2023-02-19 00:32:03 +00:00
|
|
|
outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1);
|
|
|
|
|
2022-12-20 15:55:24 +00:00
|
|
|
// Queue the outputMessage:
|
2023-02-19 00:32:03 +00:00
|
|
|
pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(listMessage, 0, sizeof(userMessage));
|
2022-10-16 15:13:33 +00:00
|
|
|
charCount = 0;
|
2023-02-19 00:32:03 +00:00
|
|
|
addNewline = false;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-15 21:43:13 +00:00
|
|
|
else if (addNewline)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
strncat(listMessage->messageContent, "|\n", 3);
|
2022-10-16 15:13:33 +00:00
|
|
|
charCount++;
|
|
|
|
addNewline = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
addNewline = true;
|
2023-02-19 00:32:03 +00:00
|
|
|
}
|
|
|
|
skillIndex++;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2022-12-20 15:55:24 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
2023-02-19 00:32:03 +00:00
|
|
|
outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1);
|
|
|
|
|
2022-12-20 15:55:24 +00:00
|
|
|
// Queue the outputMessage:
|
2023-02-19 00:32:03 +00:00
|
|
|
pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
free(listMessage);
|
|
|
|
free(formattedString);
|
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-20 23:30:41 +00:00
|
|
|
// Shout command: Allows the player to talk to everyone in the area if they are in a conversation.
|
|
|
|
case 220952831:
|
|
|
|
{
|
|
|
|
// Allocate an array of playerInfo to store the current players in the area for the output message:
|
|
|
|
playerInfo ** recipients = calloc(PLAYERCOUNT, sizeof(playerInfo*));
|
|
|
|
|
|
|
|
// Initialize them all to NULL:
|
|
|
|
for (int index = 0; index < PLAYERCOUNT; index++)
|
|
|
|
{
|
|
|
|
recipients[index] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the players in the current area and add them to our array:
|
|
|
|
int recipientIndex = 0;
|
|
|
|
for (int playerIndex = 0; playerIndex < *parameters->playerCount; playerIndex++)
|
|
|
|
{
|
|
|
|
if (parameters->connectedPlayers[playerIndex].currentArea == currentCommand->caller->currentArea)
|
|
|
|
{
|
|
|
|
recipients[recipientIndex] = ¶meters->connectedPlayers[playerIndex];
|
|
|
|
recipientIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a userMessage to be filled with the data from the command's arguments and caller:
|
|
|
|
userMessage * shoutMessage = calloc(1, sizeof(userMessage));
|
|
|
|
|
|
|
|
// Copy in the data and terminate it:
|
|
|
|
strncpy(shoutMessage->senderName, currentCommand->caller->playerName, 32);
|
|
|
|
shoutMessage->senderName[31] = '\0';
|
|
|
|
strncpy(shoutMessage->messageContent, currentCommand->arguments, MAX);
|
|
|
|
shoutMessage->messageContent[MAX - 1] = '\0';
|
|
|
|
strncat(shoutMessage->messageContent, "\n", MAX);
|
|
|
|
|
|
|
|
// Create the outputMessage for the queue:
|
|
|
|
outputMessage * shoutOutputMessage = createTargetedOutputMessage(shoutMessage, recipients, recipientIndex);
|
|
|
|
|
|
|
|
// Push the message onto the output queue:
|
|
|
|
pushQueue(parameters->outputQueue, shoutOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the array:
|
|
|
|
free(recipients);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
// Talk command: Allows the player to begin a chat session with another player:
|
2023-02-19 22:13:06 +00:00
|
|
|
case 6012644:
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 22:13:06 +00:00
|
|
|
userMessage * talkMessage = calloc(1, sizeof(userMessage));
|
2023-02-19 00:32:03 +00:00
|
|
|
talkMessage->senderName[0] = '\0';
|
|
|
|
|
2023-02-19 22:13:06 +00:00
|
|
|
// If there's no name specified, end the current chat sessions.
|
|
|
|
if (currentCommand->arguments[0] == '\0' || currentCommand->arguments == NULL)
|
|
|
|
{
|
|
|
|
currentCommand->caller->talkingWith = NULL;
|
2023-02-20 23:30:41 +00:00
|
|
|
strcpy(talkMessage->messageContent, "Conversation ended.");
|
2023-02-26 00:16:07 +00:00
|
|
|
strncat(&talkMessage->senderName[1], " > ", 4);
|
2023-02-19 22:13:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int playerIndex = 0; playerIndex < *parameters->playerCount; playerIndex++)
|
|
|
|
{
|
|
|
|
if(strncmp(currentCommand->arguments, parameters->connectedPlayers[playerIndex].playerName, 31) == 0)
|
|
|
|
{
|
|
|
|
currentCommand->caller->talkingWith = &(parameters->connectedPlayers[playerIndex]);
|
|
|
|
|
|
|
|
// Fill out the message to inform the receiving user what is happening:
|
2023-02-26 00:16:07 +00:00
|
|
|
strncat(&talkMessage->senderName[1], currentCommand->caller->playerName, 27);
|
|
|
|
strncat(&talkMessage->senderName[1], " > ", 4);
|
2023-02-19 22:13:06 +00:00
|
|
|
strncpy(talkMessage->messageContent, currentCommand->caller->playerName, 31);
|
2023-02-20 23:30:41 +00:00
|
|
|
strcat(talkMessage->messageContent, " is talking to you.");
|
2023-02-19 22:13:06 +00:00
|
|
|
|
|
|
|
playerInfo ** recipients = calloc(1, (sizeof(playerInfo*)));
|
|
|
|
recipients[0] = &(parameters->connectedPlayers[playerIndex]);
|
|
|
|
|
|
|
|
// Allocate an outputMessage for the receiving user:
|
|
|
|
outputMessage * talkReceiverMessage = createTargetedOutputMessage(talkMessage, recipients, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, talkReceiverMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Prep the message to the calling user.
|
|
|
|
strcpy(talkMessage->messageContent, "Conversation begun with: ");
|
|
|
|
strcat(talkMessage->messageContent, parameters->connectedPlayers[playerIndex].playerName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-26 00:16:07 +00:00
|
|
|
if(talkMessage->messageContent[0] == '\0')
|
|
|
|
{
|
|
|
|
strcpy(talkMessage->messageContent, "There is no player by that name connected.");
|
|
|
|
}
|
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * talkOutputMessage = createTargetedOutputMessage(talkMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, talkOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the userMessage:
|
|
|
|
free(talkMessage);
|
|
|
|
|
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Exit command: Sends an "empty" exit message to disconnect a client:
|
|
|
|
case 5284234:
|
|
|
|
{
|
|
|
|
// Allocate a userMessage containing null characters as the first char in both fields:
|
2023-02-19 22:13:06 +00:00
|
|
|
userMessage * exitMessage = calloc(1, (sizeof(userMessage)));
|
2023-02-19 00:32:03 +00:00
|
|
|
exitMessage->senderName[0] = '\0';
|
|
|
|
exitMessage->messageContent[0] = '\0';
|
2022-12-20 15:55:24 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * exitOutputMessage = createTargetedOutputMessage(exitMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, exitOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the userMessage
|
|
|
|
free(exitMessage);
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-10-16 15:13:33 +00:00
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Join command: Allows the player to join the game given a name:
|
|
|
|
// TODO: Implement login/character creation. Will be a while:
|
|
|
|
case 5525172:
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
if (currentCommand->caller->currentArea == getFromList(parameters->areaList, 0)->area)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
bool validName = true;
|
|
|
|
for(int index = 0; index < *parameters->playerCount; index++)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
if (currentCommand->arguments[0] == '\0')
|
|
|
|
{
|
|
|
|
validName = false;
|
|
|
|
}
|
|
|
|
if (strncmp(currentCommand->arguments, parameters->connectedPlayers[index].playerName, 16) == 0)
|
|
|
|
{
|
|
|
|
validName = false;
|
|
|
|
}
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
if (validName)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-19 00:32:03 +00:00
|
|
|
strncpy(currentCommand->caller->playerName, currentCommand->arguments, 16);
|
|
|
|
currentCommand->caller->currentArea = getFromList(parameters->areaList, 1)->area;
|
2023-02-26 00:16:07 +00:00
|
|
|
|
|
|
|
// Allocate a userMessage containing null characters as the first char in both fields:
|
|
|
|
userMessage * joinMessage = calloc(1, (sizeof(userMessage)));
|
|
|
|
memcpy(joinMessage->senderName, "\0 > \0", 5);
|
|
|
|
strcpy(joinMessage->messageContent, "Logged in successfully.");
|
|
|
|
|
|
|
|
// Allocate an outputMessage for the queue:
|
|
|
|
outputMessage * joinOutputMessage = createTargetedOutputMessage(joinMessage, ¤tCommand->caller, 1);
|
|
|
|
|
|
|
|
// Queue the outputMessage:
|
|
|
|
pushQueue(parameters->outputQueue, joinOutputMessage, OUTPUT_MESSAGE);
|
|
|
|
|
|
|
|
// Free the userMessage
|
|
|
|
free(joinMessage);
|
|
|
|
|
2023-02-19 00:32:03 +00:00
|
|
|
// Call the look command after joining. It's fine to unlock, because the loop won't
|
|
|
|
// continue until the command is queued:
|
|
|
|
queue->lock = false;
|
|
|
|
queueCommand(queue, "look", "", 5, 0, currentCommand->caller);
|
|
|
|
queue->lock = true;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
break;
|
2022-10-16 15:13:33 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
|
2022-10-16 15:13:33 +00:00
|
|
|
// Remove the current command and unlock the queue:
|
2023-02-25 19:51:47 +00:00
|
|
|
memset(currentCommand->command, 0, sizeof(char) * 16);
|
|
|
|
memset(currentCommand->arguments, 0, sizeof(char) * MAX);
|
2022-10-16 15:13:33 +00:00
|
|
|
currentCommand = NULL;
|
|
|
|
queue->lock = false;
|
2023-02-13 17:23:30 +00:00
|
|
|
popQueue(queue);
|
2022-10-16 15:13:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Run a stat check for the given player, returning an outcome:
|
2022-10-16 15:13:33 +00:00
|
|
|
outcome statCheck(playerInfo * player, int chance, coreStat statToCheck)
|
|
|
|
{
|
2022-10-30 12:58:39 +00:00
|
|
|
// Calculate the chance:
|
2023-02-15 21:43:13 +00:00
|
|
|
if (chance > 100 || chance < 0)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
chance = 100 - chance;
|
2022-10-30 12:58:39 +00:00
|
|
|
|
|
|
|
// Calculate the modifier:
|
2022-10-16 15:13:33 +00:00
|
|
|
int modifier = 0;
|
|
|
|
switch(statToCheck)
|
|
|
|
{
|
|
|
|
case WITS:
|
|
|
|
{
|
|
|
|
modifier = player->stats->wits * 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case INTELLECT:
|
|
|
|
{
|
|
|
|
modifier = player->stats->intellect * 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case STRENGTH:
|
|
|
|
{
|
|
|
|
modifier = player->stats->strength * 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ENDURANCE:
|
|
|
|
{
|
|
|
|
modifier = player->stats->endurance * 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DEXERITY:
|
|
|
|
{
|
|
|
|
modifier = player->stats->dexerity * 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
}
|
2023-02-25 19:51:47 +00:00
|
|
|
int attempt = (rand() % 100) + modifier;
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt >= chance)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt >= 98)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
return CRITICAL_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt <= 2)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
return CRITICAL_FAILURE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Run a skill check for the given player, returning an outcome:
|
2022-11-29 21:04:36 +00:00
|
|
|
outcome skillCheck(playerInfo * player, int chance, char * skillName, size_t skillNameLength, list * globalSkillList)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
// Calculate the chance:
|
2023-02-15 21:43:13 +00:00
|
|
|
if (chance > 100 || chance < 0)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
chance = 100 - chance;
|
|
|
|
|
|
|
|
// Check if the player has the given skill:
|
|
|
|
bool playerHasSkill = false;
|
2022-11-29 21:04:36 +00:00
|
|
|
size_t playerIndex = 0;
|
2023-02-15 21:43:13 +00:00
|
|
|
while (playerIndex < player->skills->itemCount)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (strncmp(skillName, getFromList(player->skills, playerIndex)->skill->skillName, skillNameLength) != 0)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
playerHasSkill = true;
|
|
|
|
break;
|
|
|
|
}
|
2022-11-29 21:04:36 +00:00
|
|
|
playerIndex++;
|
2022-10-30 12:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the player doesn't have the skill, check if it's in the game and is trained:
|
|
|
|
bool trainedSkill = false;
|
2022-11-29 21:04:36 +00:00
|
|
|
size_t globalIndex = 0;
|
2023-02-15 21:43:13 +00:00
|
|
|
while (globalIndex < globalSkillList->itemCount)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (strncmp(skillName, getFromList(globalSkillList, globalIndex)->skill->skillName, skillNameLength) != 0)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
2022-11-29 21:04:36 +00:00
|
|
|
trainedSkill = getFromList(globalSkillList, globalIndex)->skill->trainedSkill;
|
|
|
|
break;
|
2022-10-30 12:58:39 +00:00
|
|
|
}
|
2022-11-29 21:04:36 +00:00
|
|
|
globalIndex++;
|
2022-10-30 12:58:39 +00:00
|
|
|
}
|
2022-11-29 21:04:36 +00:00
|
|
|
|
2022-10-30 12:58:39 +00:00
|
|
|
// Calculate the modifier:
|
|
|
|
int modifier = 0;
|
2023-02-15 21:43:13 +00:00
|
|
|
if (trainedSkill)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
modifier = -100;
|
|
|
|
}
|
2023-02-15 21:43:13 +00:00
|
|
|
else if (playerHasSkill)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
2022-11-29 21:04:36 +00:00
|
|
|
modifier = getFromList(player->skills, playerIndex)->skill->skillModifier * 4;
|
2022-10-30 12:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt the check:
|
2023-02-25 19:51:47 +00:00
|
|
|
int attempt = (rand() % 100) + modifier;
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt >= chance)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt >= 98)
|
2022-10-30 12:58:39 +00:00
|
|
|
{
|
|
|
|
return CRITICAL_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (attempt <= 2)
|
2022-10-16 15:13:33 +00:00
|
|
|
{
|
|
|
|
return CRITICAL_FAILURE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 21:43:13 +00:00
|
|
|
// Move a player along a path in their current area:
|
2022-10-23 16:07:13 +00:00
|
|
|
int movePlayerToArea(playerInfo * player, char * requestedPath)
|
|
|
|
{
|
|
|
|
// Check if a number was given first:
|
2022-11-13 00:23:42 +00:00
|
|
|
size_t selected = atoi(requestedPath);
|
2023-02-15 21:43:13 +00:00
|
|
|
if (selected != 0 && !(selected > player->currentArea->pathList->itemCount))
|
2022-10-23 16:07:13 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (getFromList(player->currentArea->pathList, selected - 1)->path != NULL &&
|
2023-02-19 00:32:03 +00:00
|
|
|
getFromList(player->currentArea->pathList, selected - 1)->path->areaToJoin != NULL)
|
2022-10-23 16:07:13 +00:00
|
|
|
{
|
2022-11-13 00:23:42 +00:00
|
|
|
player->currentArea = getFromList(player->currentArea->pathList, selected - 1)->path->areaToJoin;
|
2022-10-23 16:07:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise search for the description:
|
2022-11-13 00:23:42 +00:00
|
|
|
for (size_t index = 0; index < player->currentArea->pathList->itemCount; index++)
|
2022-10-23 16:07:13 +00:00
|
|
|
{
|
2023-02-15 21:43:13 +00:00
|
|
|
if (strncmp(getFromList(player->currentArea->pathList, index)->path->pathName,
|
2023-02-19 00:32:03 +00:00
|
|
|
requestedPath, 32) == 0)
|
2022-10-23 16:07:13 +00:00
|
|
|
{
|
2022-11-13 00:23:42 +00:00
|
|
|
player->currentArea = getFromList(player->currentArea->pathList, index)->path->areaToJoin;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2022-10-23 16:07:13 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2023-02-19 00:32:03 +00:00
|
|
|
|
|
|
|
// A hash function for distinguishing commands for the game logic handler:
|
|
|
|
unsigned int hashCommand(char * command, unsigned int commandLength)
|
|
|
|
{
|
|
|
|
unsigned int hash = 0;
|
|
|
|
char * currentCharacter = command;
|
|
|
|
|
|
|
|
for (unsigned int index = 0; index < commandLength && *currentCharacter != '\0'; currentCharacter++)
|
|
|
|
{
|
|
|
|
hash = 37 * hash + *currentCharacter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|