2023-03-25 21:38:00 +00:00
|
|
|
// schemeintegration.h: Function definitions for SilverMUD's Scheme integration.
|
|
|
|
// Barra Ó Catháin, 2023.
|
2023-04-07 21:13:45 +00:00
|
|
|
#include <string.h>
|
2023-03-25 21:38:00 +00:00
|
|
|
#include <libguile.h>
|
|
|
|
#include "schemeintegration.h"
|
|
|
|
|
2023-04-06 22:09:20 +00:00
|
|
|
// Create a player skill and add it to a given skill list from Scheme:
|
2023-03-25 23:56:25 +00:00
|
|
|
SCM scheme_create_skill(SCM string, SCM skilllist)
|
2023-04-06 22:09:20 +00:00
|
|
|
{
|
2023-03-25 23:56:25 +00:00
|
|
|
size_t skillNameLength = 0;
|
|
|
|
char * skillName = scm_to_latin1_stringn(string, &skillNameLength);
|
|
|
|
createSkill(scm_to_pointer(skilllist), skillName, skillNameLength, false);
|
|
|
|
free(skillName);
|
|
|
|
return SCM_BOOL_T;
|
|
|
|
}
|
|
|
|
|
2023-04-07 21:49:15 +00:00
|
|
|
// Change the name of an existing area in a list, given the number of the area in the list, from Scheme:
|
|
|
|
SCM scheme_change_area_name(SCM newname, SCM areanumber, SCM arealist)
|
|
|
|
{
|
|
|
|
// Check if the area exists:
|
|
|
|
list * areaList = scm_to_pointer(arealist);
|
|
|
|
size_t areaNumber = scm_to_size_t(areanumber);
|
|
|
|
|
|
|
|
if (areaList->type != AREA)
|
|
|
|
{
|
|
|
|
return SCM_BOOL_F;
|
|
|
|
}
|
|
|
|
|
|
|
|
playerArea * area = getFromList(areaList, areaNumber)->area;
|
|
|
|
|
|
|
|
if (area == NULL)
|
|
|
|
{
|
|
|
|
return SCM_BOOL_F;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a string from the Scheme string and copy it into the area:
|
|
|
|
size_t newNameLength = 0;
|
|
|
|
char * newName = scm_to_locale_stringn(newname, &newNameLength);
|
|
|
|
memset(area->areaName, 0, 32);
|
|
|
|
if (newNameLength > 32)
|
|
|
|
{
|
|
|
|
memcpy(area->areaName, newName, 31);
|
|
|
|
area->areaName[31] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(area->areaName, newName, newNameLength);
|
|
|
|
area->areaName[31] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
free(newName);
|
|
|
|
|
|
|
|
return SCM_BOOL_T;
|
|
|
|
}
|
|
|
|
|
2023-04-07 21:13:45 +00:00
|
|
|
// Change the description of an existing area in a list, given the number of the area in the list, from Scheme:
|
|
|
|
SCM scheme_change_area_description(SCM newdescription, SCM areanumber, SCM arealist)
|
|
|
|
{
|
|
|
|
// Check if the area exists:
|
|
|
|
list * areaList = scm_to_pointer(arealist);
|
|
|
|
size_t areaNumber = scm_to_size_t(areanumber);
|
|
|
|
|
|
|
|
if (areaList->type != AREA)
|
|
|
|
{
|
|
|
|
return SCM_BOOL_F;
|
|
|
|
}
|
|
|
|
|
|
|
|
playerArea * area = getFromList(areaList, areaNumber)->area;
|
|
|
|
|
|
|
|
if (area == NULL)
|
|
|
|
{
|
|
|
|
return SCM_BOOL_F;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a string from the Scheme string and copy it into the area:
|
|
|
|
size_t newDescriptionLength = 0;
|
|
|
|
char * newDescription = scm_to_locale_stringn(newdescription, &newDescriptionLength);
|
|
|
|
memset(area->areaDescription, 0, MAX - 35);
|
|
|
|
if (newDescriptionLength > MAX - 35)
|
|
|
|
{
|
|
|
|
memcpy(area->areaDescription, newDescription, MAX - 35);
|
2023-04-07 21:49:15 +00:00
|
|
|
area->areaDescription[MAX - 36] = '\0';
|
2023-04-07 21:13:45 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(area->areaDescription, newDescription, newDescriptionLength);
|
2023-04-07 21:49:15 +00:00
|
|
|
area->areaDescription[MAX - 36] = '\0';
|
2023-04-07 21:13:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(newDescription);
|
|
|
|
|
|
|
|
return SCM_BOOL_T;
|
|
|
|
}
|
|
|
|
|
2023-04-06 22:09:20 +00:00
|
|
|
// Message every currently connected player from Scheme:
|
2023-04-05 20:34:57 +00:00
|
|
|
SCM scheme_message_everyone(SCM sendername, SCM messagecontent, SCM outputqueue)
|
|
|
|
{
|
2023-04-06 22:09:20 +00:00
|
|
|
// Allocate the memory for the needed data structures:
|
2023-04-05 20:34:57 +00:00
|
|
|
outputMessage * newOutputMessage = calloc(1, sizeof(userMessage));
|
|
|
|
userMessage * newMessage = calloc(1, sizeof(userMessage));
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Set some basic information for the output message, allowing it to be sent to everyone:
|
2023-04-05 20:34:57 +00:00
|
|
|
newOutputMessage->content = newMessage;
|
|
|
|
newOutputMessage->recipientsCount = 0;
|
|
|
|
newOutputMessage->recipients = NULL;
|
|
|
|
|
2023-04-06 22:09:20 +00:00
|
|
|
// Convert the Scheme strings to C strings, and ensure they're NULL terminated:
|
2023-04-05 20:34:57 +00:00
|
|
|
scm_to_locale_stringbuf(sendername, newMessage->senderName, 31);
|
|
|
|
newMessage->senderName[31] = '\0';
|
|
|
|
scm_to_locale_stringbuf(messagecontent, newMessage->messageContent, MAX - 1);
|
|
|
|
newMessage->messageContent[MAX - 1] = '\0';
|
|
|
|
|
2023-04-06 22:09:20 +00:00
|
|
|
// Clean up the message contents to ensure they're safe to send and display correctly:
|
2023-04-05 20:34:57 +00:00
|
|
|
userNameSanatize(newMessage->senderName, 32);
|
|
|
|
userInputSanatize(newMessage->messageContent, MAX);
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Push it to the queue, where it will be handled and de-allocated:
|
2023-04-05 20:34:57 +00:00
|
|
|
pushQueue(scm_to_pointer(outputqueue), newOutputMessage, OUTPUT_MESSAGE);
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Return a Scheme #t value:
|
2023-04-05 20:34:57 +00:00
|
|
|
return SCM_BOOL_T;
|
|
|
|
}
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// The function ran by the Scheme thread which handles all game-master and interpreter interaction:
|
2023-03-25 21:38:00 +00:00
|
|
|
void * schemeHandler(void * parameters)
|
|
|
|
{
|
2023-04-06 22:09:20 +00:00
|
|
|
// Take in the needed values from the main thread and make it back into the struct:
|
2023-03-25 23:56:25 +00:00
|
|
|
SchemeThreadParameters * schemeThreadParameters = parameters;
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Initialize GNU Guile:
|
2023-03-25 23:56:25 +00:00
|
|
|
scm_init_guile();
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Register the various functions:
|
2023-03-25 23:56:25 +00:00
|
|
|
scm_c_define_gsubr("create-skill", 2, 0, 0, &scheme_create_skill);
|
2023-04-05 20:34:57 +00:00
|
|
|
scm_c_define_gsubr("message-everyone", 3, 0, 0, &scheme_message_everyone);
|
2023-04-07 21:49:15 +00:00
|
|
|
scm_c_define_gsubr("change-area-name", 3, 0, 0, &scheme_change_area_name);
|
2023-04-07 21:13:45 +00:00
|
|
|
scm_c_define_gsubr("change-area-description", 3, 0, 0, &scheme_change_area_description);
|
|
|
|
|
2023-04-06 22:09:20 +00:00
|
|
|
// Define the various game state pointers as Scheme objects:
|
2023-04-07 21:13:45 +00:00
|
|
|
scm_c_define("area-list", scm_from_pointer(schemeThreadParameters->areaList, NULL));
|
2023-03-25 23:56:25 +00:00
|
|
|
scm_c_define("skill-list", scm_from_pointer(schemeThreadParameters->skillList, NULL));
|
2023-04-05 20:34:57 +00:00
|
|
|
scm_c_define("output-queue", scm_from_pointer(schemeThreadParameters->outputQueue, NULL));
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Drop into the Scheme interpreter:
|
2023-03-25 21:38:00 +00:00
|
|
|
scm_shell(0, NULL);
|
2023-04-06 22:09:20 +00:00
|
|
|
|
|
|
|
// Return NULL. This should be unreachable.
|
|
|
|
return NULL;
|
2023-03-25 21:38:00 +00:00
|
|
|
}
|
2023-03-25 23:56:25 +00:00
|
|
|
|