News:

Welcome to RetroCoders Community

Main Menu

Recent posts

#1
General Discussion / Re: Personal Site dedicated to...
Last post by ron77 - Today at 01:44 PM
aural, you are THIS CLOSE to getting banned and kicked from here... there is no place here for toxic people like you. You are one of the main reasons this forum is abandoned

I'm warning you for the last time...

ron77
#2
General Discussion / Re: Personal Site dedicated to...
Last post by aurel - Dec 01, 2024, 05:09 PM
or in code tags:

Sub setupArgs(nArgs As Integer)
    getLeftParen()
    Dim i As Integer = topOfStack
    Dim count As Integer = nArgs
    If nextToken() <> ")" Then
        Do
            getToken()
          If i >= 0 Then
                stack(i).symTabIndex = tokenAddress
            End If
            i = i - 1
            count = count - 1
          getToken()
      Loop While token = ","
        putTokenBack()
    End If
    If count <> 0 Then
        error(nArgs & " argument" & If(nArgs = 1, "", "s") & " expected")
    End If
    getRightParen()
 End Sub
#3
General Discussion / Re: Personal Site dedicated to...
Last post by aurel - Dec 01, 2024, 05:05 PM
Hey Ron

i read somewhere that you offer a help in FreeBasic programming
so may I ask you ..are you maybe ready for challenge to translate
and explain what this code do:

Sub setupArgs(nArgs As Integer)
    getLeftParen()
    Dim i As Integer = topOfStack
    Dim count As Integer = nArgs
    If nextToken() <> ")" Then
        Do
            getToken()
          If i >= 0 Then
                stack(i).symTabIndex = tokenAddress
            End If
            i -= 1
            count -= 1
          getToken()
      Loop While token = ","
        putTokenBack()
    End If
    If count <> 0 Then
        error(nArgs & " argument" & If(nArgs = 1, "", "s") & " expected")
    End If
    getRightParen()
 End Sub
#4
PowerBasic / PowerBasic Site seem to be off...
Last post by ron77 - Nov 22, 2024, 06:53 PM
PowerBasic company, which sells PBCC AND PBWIN Compilers and other Products, seems to be offline ... they do not sell the compilers anymore. While the PB community forum appears alive, it seems that Powerbasic has reached a DEAD END.... It looks like the company behind it is closing its business :(

Another BASIC programming language has ceased to exist.

RIP POWERBASIC
#5
C / C++ Game Dev / homeless game in Hebrew with S...
Last post by ron77 - Nov 19, 2024, 12:13 PM
Hello, I converted my C game "Homeless Surviving the Streets" into Hebrew and made it a graphic SDL2 game



Here is the code: (p.s. - I'm on Windows and using Windows fonts with Hebrew compatibility)

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <windows.h>
#include <wchar.h>
#include <locale.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define FONT_SIZE 20
#define MAX_STRING_LENGTH 1024

// Game state
int health = 75, money = 50, turns = 1;
bool isOver = false;

// SDL globals
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
TTF_Font* font = NULL;

// Hebrew print context
typedef struct {
    SDL_Renderer* renderer;
    TTF_Font* font;
    SDL_Color textColor;
    int xPos;
    int yPos;
} HebrewPrintContext;

HebrewPrintContext* hbPrint = NULL;
// Add this with your other constant definitions at the top of the file
const char* MENU_OPTIONS[] = {
    "1. לבקש נדבות או כסף ברחוב",
    "2. להתקשר למישהו לעזרה",
    "3. לחפש מקום לישון",
    "4. לחפש עבודה",
    "5. לקנות סמים או אלכוהול"
};

// Also make sure you have these status text constants
const char* WINDOW_TITLE = "משחק הישרדות ברחוב";
const char* DAYS_TEXT = "ימים ברחוב:";
const char* HEALTH_TEXT = "בריאות:";
const char* MONEY_TEXT = "כסף:";
const char* GAME_OVER_TEXT = "המשחק נגמר!";

// Original, longer Hebrew text arrays
const char* call[] = {
    "את/ה מתקשר/ת לסבתא שלך ושניכם בוכים... היא מבטיחה לנסות להשיג לך עזרה... היא שולחת את אהבתה... את/ה מבטיח/ה לשמור על קשר איתה",
    "התקשרת לחברה והיא נתנה לך קצת כסף ונתנה לך להישאר אצלה ללילה... זכית במקלחת טובה בגדים נקיים וארוחה טובה ואתה שוב ברחוב",
    "התקשרת למספר של קו חם לעזרה לדרי רחוב... הם באים לאסוף אותך נותנים אוכל ומחסה ללילה אתה מדבר עם עובד סוציאלי והוא נותן לך את המספר שלו למקרה שתצטרך",
    "התקשרת לקרוב משפחה אבל אף אחד לא עונה... נשארת לבד ברחוב",
    "התקשרת למשפחה והם באים לקחת אותך ונותנים לך להישאר כמה שצריך... אתה יורד מהרחוב",
    "התקשרת אבל אין תשובה"
};

const char* shelter[] = {
    "הלכת למקלט לדרי רחוב... נשדדת מהכסף שלך על ידי מכורים אלימים... הצלחת לברוח משם ובילית את שארית הלילה בפארק בוכה",
    "ניסית לישון בפארק אבל נעצרת על ידי שוטר... בילית כמה שעות בכלא שם הוכית על ידי אסירים... בבוקר אתה שוב ברחוב",
    "יש לך מספיק כסף לשכור חדר במוטל ללילה... אתה מתקלח ומכבס את הבגדים שלך וישן במיטה חמה וחולם שיש לך בית",
    "ישנת בפארק על ספסל שם קפאת למוות בגלל מזג האוויר הקר... אתה עכשיו בגן עדן מנוח על משכבך בשלום",
    "ישנת ברחוב בפינה כשאתה מתעורר אתה מוצא שטר של 20 שקל ופתק שאומר 'שאלוהים יעזור לך זה המעט שאני יכול לעשות'",
    "נעצרת על ידי המשטרה ועכשיו במקום לשרוד ברחוב אתה צריך לשרוד בכלא"
};

const char* beg[] = {
    "ישבת שעות ואנשים עוברים על פניך כאילו אתה שקוף ואז איזו גברת נחמדה באה ומזמינה אותך לאכול על חשבונה... אתה מדבר איתה שעתיים ומספר לה את הסיפור שלך... ואז היא אומרת 'ביי'",
    "ישבת בפינה ואנשים נתנו לך מטבעות ושטרות קיבלת מספיק כסף להסתדר לכמה ימים",
    "ישבת ואיזה אדם מציע לך עבודה תמורת כסף וארוחה אתה מסכים... אתה הולך לביתו ועוזר לו לצבוע את ביתו ואז הוא נותן לך 10 שקל וארוחה ביתית",
    "אף אחד לא נותן לך כלום! אתה רעב ואין לך ברירה אלא לחפש אוכל בזבל... אתה נהיה חולה... מאוד חולה ואתה מת ברחוב מהרעלת מזון... מנוח על משכבך בשלום",
    "ישבת כל היום בשביל כלום אף אחד לא נתן לך כלום"
};

const char* work[] = {
    "ניסית למצוא עבודה אבל אף אחד לא מעוניין",
    "מצאת עבודה כשוטף כלים במסעדה אחרי שבוע אתה יכול להרשות לעצמך מקום לקרוא לו בית. אתה יורד מהרחוב!",
    "מצאת עבודה אבל פוטרת ממש מהר"
};

const char* drugs[] = {
    "השתכרת והתאבנת מאלכוהול זול ולכמה שעות שכחת מכל הבעיות שלך",
    "לקחת סמים זולים מהרחוב ונהיית חולה והתמוטטת ברחוב... התעוררת בבית חולים וכשהיית בסדר אתה שוב ברחוב",
    "התאבנת ואיבדת הכרה כשאתה מתעורר בבוקר כל מה שהיה לך נעלם - נשדדת",
    "לקחת סמים ועשית אוברדוז ומת ברחוב מנוח על משכבך בשלום"
};


// Function to reverse UTF-8 Hebrew string properly
void reverseHebrewUTF8(char* str) {
    if (!str) return;
    
    int len = strlen(str);
    char* temp = (char*)malloc(len + 1);
    if (!temp) return;
    
    int i = 0;
    int j = len;
    
    temp[j] = '\0';
    
    while (i < len) {
        if ((str[i] & 0xC0) == 0x80) {
            i++;
            continue;
        }
        
        int char_len = 1;
        if ((str[i] & 0xE0) == 0xC0) char_len = 2;
        else if ((str[i] & 0xF0) == 0xE0) char_len = 3;
        else if ((str[i] & 0xF8) == 0xF0) char_len = 4;
        
        j -= char_len;
        memcpy(temp + j, str + i, char_len);
        i += char_len;
    }
    
    strcpy(str, temp);
    free(temp);
}

HebrewPrintContext* createPrintContext(SDL_Renderer* renderer, const char* fontPath, int fontSize) {
    HebrewPrintContext* context = (HebrewPrintContext*)malloc(sizeof(HebrewPrintContext));
    if (!context) return NULL;
    
    context->renderer = renderer;
    context->font = TTF_OpenFont(fontPath, fontSize);
    context->textColor = (SDL_Color){255, 255, 255, 255};
    context->xPos = WINDOW_WIDTH - 20;
    context->yPos = 20;
    
    return context;
}

// Add this helper function to check if a string is just a number
bool isNumber(const char* str) {
    while (*str) {
        if (*str < '0' || *str > '9') return false;
        str++;
    }
    return true;
}

void printRight(HebrewPrintContext* context, const char* format, ...) {
    if (!context || !context->font || !context->renderer) return;
    
    va_list args;
    va_start(args, format);
    char buffer[MAX_STRING_LENGTH];
    vsnprintf(buffer, MAX_STRING_LENGTH, format, args);
    va_end(args);
    
    char text[MAX_STRING_LENGTH] = "";
    char number[32] = "";
    int textWidth = 0;  // Store text width for later use
    
    // Find where the number starts (if any)
    char* numberStart = strrchr(buffer, ' ');
    if (numberStart) {
        // Check if what follows the space is a number
        if (isNumber(numberStart + 1)) {
            strncpy(text, buffer, numberStart - buffer);
            text[numberStart - buffer] = '\0';
            strcpy(number, numberStart + 1);
        } else {
            strcpy(text, buffer);
        }
    } else {
        if (isNumber(buffer)) {
            strcpy(number, buffer);
        } else {
            strcpy(text, buffer);
        }
    }
    
    // Render Hebrew text if present
    SDL_Surface* textSurface = NULL;
    if (text[0] != '\0') {
        reverseHebrewUTF8(text);
        textSurface = TTF_RenderUTF8_Blended(context->font, text, context->textColor);
        if (textSurface) {
            SDL_Texture* textTexture = SDL_CreateTextureFromSurface(context->renderer, textSurface);
            if (textTexture) {
                SDL_Rect destRect = {
                    context->xPos - textSurface->w,
                    context->yPos,
                    textSurface->w,
                    textSurface->h
                };
                SDL_RenderCopy(context->renderer, textTexture, NULL, &destRect);
                textWidth = textSurface->w;  // Save the width
                SDL_DestroyTexture(textTexture);
            }
            SDL_FreeSurface(textSurface);
        }
    }
    
    // Render number if present
    if (number[0] != '\0') {
        SDL_Surface* numSurface = TTF_RenderUTF8_Blended(context->font, number, context->textColor);
        if (numSurface) {
            SDL_Texture* numTexture = SDL_CreateTextureFromSurface(context->renderer, numSurface);
            if (numTexture) {
                SDL_Rect destRect = {
                    context->xPos - textWidth - numSurface->w - (text[0] ? 5 : 0),
                    context->yPos,
                    numSurface->w,
                    numSurface->h
                };
                SDL_RenderCopy(context->renderer, numTexture, NULL, &destRect);
                SDL_DestroyTexture(numTexture);
            }
            SDL_FreeSurface(numSurface);
        }
    }
    
    // Move to next line
    context->yPos += TTF_FontHeight(context->font) + 5;
}

void setPrintColor(HebrewPrintContext* context, Uint8 r, Uint8 g, Uint8 b) {
    if (!context) return;
    context->textColor.r = r;
    context->textColor.g = g;
    context->textColor.b = b;
}

void setPrintPosition(HebrewPrintContext* context, int x, int y) {
    if (!context) return;
    context->xPos = x;
    context->yPos = y;
}

char* getRandomResult(const char* array[], int size) {
    return (char*)array[rand() % size];
}

void renderGameState() {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, 20);
    setPrintColor(hbPrint, 255, 255, 255);
    
    // Print status
    printRight(hbPrint, "%s %d", DAYS_TEXT, turns);
    printRight(hbPrint, "%s %d", HEALTH_TEXT, health);
    printRight(hbPrint, "%s %d", MONEY_TEXT, money);
    
    // Print menu
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, 120);
    for (int i = 0; i < 5; i++) {
        printRight(hbPrint, "%s", MENU_OPTIONS[i]);
    }
    
    SDL_RenderPresent(renderer);
}

void renderResult(const char* text) {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
    
    // Split long text into multiple lines
    char buffer[MAX_STRING_LENGTH];
    strncpy(buffer, text, MAX_STRING_LENGTH - 1);
    buffer[MAX_STRING_LENGTH - 1] = '\0';
    
    setPrintPosition(hbPrint, WINDOW_WIDTH - 20, WINDOW_HEIGHT / 3);
    setPrintColor(hbPrint, 255, 255, 255);
    
    // Split by dots and print each part
    char* line = strtok(buffer, "...");
    while (line != NULL) {
        // Trim any leading whitespace
        while (*line == ' ') line++;
        
        if (strlen(line) > 0) {
            printRight(hbPrint, "%s...", line);
            // Move to next line position (printRight already updates yPos)
            
            setPrintPosition(hbPrint, WINDOW_WIDTH - 20, hbPrint->yPos);
        }
        line = strtok(NULL, "...");
    }
    
    SDL_RenderPresent(renderer);
    SDL_Delay(15000);
}

bool handleGameAction(int choice) {
    char* result = NULL;
    
    switch(choice) {
        case 1:
            result = getRandomResult((const char**)beg, 5);
            if (result == beg[3]) isOver = true;
            break;
        case 2:
            result = getRandomResult((const char**)call, 6);
            if (result == call[4]) isOver = true;
            break;
        case 3:
            result = getRandomResult((const char**)shelter, 6);
            if (result == shelter[3]) isOver = true;
            break;
        case 4:
            result = getRandomResult((const char**)work, 3);
            if (result == work[1]) isOver = true;
            break;
        case 5:
            result = getRandomResult((const char**)drugs, 4);
            if (result == drugs[3]) isOver = true;
            break;
        default:
            return false;
    }

    if (result) {
        renderResult(result);
        return true;
    }
    
    return false;
}

bool init() {
    // Set locale for UTF-8
    setlocale(LC_ALL, "he_IL.UTF-8");
    
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL initialization failed: %s\n", SDL_GetError());
        return false;
    }

    if (TTF_Init() < 0) {
        printf("SDL_ttf initialization failed: %s\n", TTF_GetError());
        return false;
    }

    window = SDL_CreateWindow(WINDOW_TITLE,
                            SDL_WINDOWPOS_UNDEFINED,
                            SDL_WINDOWPOS_UNDEFINED,
                            WINDOW_WIDTH, WINDOW_HEIGHT,
                            SDL_WINDOW_SHOWN);
    if (!window) {
        printf("Window creation failed: %s\n", SDL_GetError());
        return false;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        printf("Renderer creation failed: %s\n", SDL_GetError());
        return false;
    }

    // Try multiple Hebrew fonts
    const char* fontPaths[] = {
        "C:\\Windows\\Fonts\\arial.ttf",
        "C:\\Windows\\Fonts\\david.ttf",
        "C:\\Windows\\Fonts\\miriam.ttf"
    };
    
    hbPrint = NULL;
    for (int i = 0; i < sizeof(fontPaths)/sizeof(fontPaths[0]); i++) {
        hbPrint = createPrintContext(renderer, fontPaths[i], FONT_SIZE);
        if (hbPrint && hbPrint->font) break;
        if (hbPrint) {
            free(hbPrint);
            hbPrint = NULL;
        }
    }
    
    if (!hbPrint) {
        printf("Failed to create Hebrew print context\n");
        return false;
    }

    srand((unsigned int)time(NULL));
    return true;
}

void cleanup() {
    if (hbPrint) {
        if (hbPrint->font) TTF_CloseFont(hbPrint->font);
        free(hbPrint);
    }
    if (renderer) SDL_DestroyRenderer(renderer);
    if (window) SDL_DestroyWindow(window);
    TTF_Quit();
    SDL_Quit();
}

int main(int argc, char* argv[]) {
    if (!init()) {
        cleanup();
        return 1;
    }

    SDL_Event event;
    bool quit = false;

    while (!quit && !isOver && health > 0) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }
            else if (event.type == SDL_KEYDOWN) {
                int choice = 0;
                switch (event.key.keysym.sym) {
                    case SDLK_1: choice = 1; break;
                    case SDLK_2: choice = 2; break;
                    case SDLK_3: choice = 3; break;
                    case SDLK_4: choice = 4; break;
                    case SDLK_5: choice = 5; break;
                }
                
                if (choice > 0) {
                    if (handleGameAction(choice)) {
                        turns++;
                        health -= 5;
                        money -= 5;
                    }
                }
            }
        }

        renderGameState();
        SDL_Delay(16);
    }

    if (!quit) {
        setPrintColor(hbPrint, 255, 0, 0);
        setPrintPosition(hbPrint, WINDOW_WIDTH - 20, WINDOW_HEIGHT/2);
        printRight(hbPrint, "%s", GAME_OVER_TEXT);
        SDL_RenderPresent(renderer);
        SDL_Delay(3000);
    }

    cleanup();
    return 0;
}

you compile it with SDL2 and SDL2_ttf libs with this npp nppexec script

npp_save
ENV_SET InputFile = $(CURRENT_DIRECTORY)\$(FILE_NAME)
ENV_SET OutDir = $(CURRENT_DIRECTORY)
ENV_SET OutputFile = $(CURRENT_DIRECTORY)\$(NAME_PART).exe
// ENV_SET InRes = $(CURRENT_DIRECTORY)\Res\NewComCtl.rc
// ENV_SET ResObj = $(CURRENT_DIRECTORY)\Res\manifest.o

cd $(CURRENT_DIRECTORY)
//cmd /c C:\mingw32\bin -i %InRes% -F pe-i386 -o %ResObj%
// cd C:\mingw32\bin
cmd /c del %OutputFile% >nul 2>&1 
// -Wpedantic %ResObj%
cmd /c gcc -Wno-unused-label -Wall -std=c99 -Wno-unknown-pragmas -O1 -Wfatal-errors -s "%InputFile%" -lmingw32 -lSDL2main -lSDL2 -lSDL2_ttf -fexec-charset=UTF-8 -luser32 -lgdi32 -IC:\c_programming\SDL2-2.30.9\i686-w64-mingw32\include -LC:\c_programming\SDL2-2.30.9\i686-w64-mingw32\lib -o "%OutputFile%
if "$(EXITCODE)" == "0" then
  cd OutDir
  cmd /c start /wait cmd " /c %OutputFile% " & pause
endif
#6
General Discussion / Re: Personal Site dedicated to...
Last post by aurel - Nov 18, 2024, 09:29 AM
why DOS..
and who made this web browser based DOS sites
you Ron?

I must say that i like your personal page ABOUT ME  :)
#7
General Discussion / Re: Personal Site dedicated to...
Last post by CharlieJV - Nov 15, 2024, 05:38 PM
That is pretty cool.
#8
General Discussion / Personal Site dedicated to DOS...
Last post by ron77 - Nov 15, 2024, 04:19 AM
hello...

well, I finally did it i opened a small website for my Dos games where you can play them online in the browser...

the games are mostly GW-BASIC and FreeBASIC for Dos games and are almost all text games...

link: Retro Dev Ronen
#9
FreeBasic / Hebrew in freeBASIC
Last post by ron77 - Oct 04, 2024, 10:07 AM
1. hebrew in freebasic GFX screen you need to load a .CPI hebrew font like so...

file "LoadFont.bas"

type fbGfxFONT
  as long w,h
  as ubyte ptr pData
  bData(16*256-1) as ubyte
end type  
extern as any ptr __fb_gfx alias "__fb_gfx"
static shared as fbGfxFONT g_MyFont = type(8,16)
static shared as fbGfxFONT ptr g_pOrgFont
static shared as fbGfxFONT ptr ptr g_pptfbGfxFont

sub LoadFontEgaCPI( sFontFile as string )
  
  g_pptfbGfxFont = cptr(fbGfxFONT ptr ptr,__fb_gfx+52+9*sizeof(any ptr)-4)  
  if g_pOrgFont = 0 then g_pOrgFont = *g_pptfbGfxFont
  *g_pptfbGfxFont = @g_MyFont  
  
  var f = freefile()
  if open(sFontFile for binary access read as #f) then exit sub
  get #f,66,g_MyFont.bData(): close #f
  for N as long = 0 to 255*16
    g_MyFont.bData(N) = ((g_MyFont.bData(N) * &h80200802ULL) and &h0884422110ULL) * &h0101010101ULL shr 32
  next N
    
  g_MyFont.pData = @(g_MyFont.bData(0))  
  
end sub
#define EnableFont() *g_pptfbGfxFont = @g_MyFont  
#define RestoreFont() *g_pptfbGfxFont = g_pOrgFont

'~ screenres 640,480

'~ width 640\8,480\16 'must be 8x16
'~ LoadFontEgaCPI("hebega.cpi")

'~ for I as long = 0 to 1
  '~ for N as long = 0 to 255
    '~ locate 1+N\16, I*40+1+(N mod 16)*2
    '~ if (N >=7 and N<=10) or N=13 then print "?";: continue for
    '~ print chr(N);    
  '~ next N  
  '~ RestoreFont()
'~ next I

'~ sleep : end

You cannot view this attachment.

Plus you need to use IBM OEM 862 encoding instead UTF-8

Here is a function that converts UTF-8 to IBM OEM 862 encoding plus a "PrintRight" Function:

function Utf8ToOEM862( sInput as string ) as string
  dim as string sOutput = space(len(sInput))
  dim as long iOut
  for N as long = 0 to len(sInput)-1
    if sInput[N]=&hD7 then
      if sInput[N+1]>=&h90 andalso sInput[N+1]<=&hAA then
        sOutput[iOut] = sInput[N+1]-&h10         
        iOut += 1 : N += 1 :  :continue for
      end if
    end if
    #if __FB_DEBUG__    
      if sInput[N]>&h7F then puts("Warning: utf-8 char not converted!")
    #endif
    sOutput[iOut] = sInput[N] : iOut += 1
  next N
  return left(sOutput,iOut)
end function


sub PrintRight( sText as string )
  var sInvert = sText, iLen = len(sInvert)-1  
  for N as long = 0 to iLen\2
    swap SInvert[N],sInvert[iLen-N]
  next N
  var iLin = csrlin(), iCol = pos()
  if (iCol-(iLen+1)) < 1 then 
    print : iLin = csrlin() : iCol = loword(width())
  end if
  locate iLin,iCol-iLen
  print sInvert;
  locate iLin,iCol-(iLen+1)
end sub

and here is a function that converts UTF-8 to ANSI 1255 (good for GUI window9.bi)

function utf8toansi1255( sInput as string ) as string
  dim as string sOutput = space(len(sInput))
  dim as long iOut
  for N as long = 0 to len(sInput)-1
    if sInput[N]=&hD7 then
      if sInput[N+1]>=&h90 andalso sInput[N+1]<=&hAA then
        sOutput[iOut] = sInput[N+1]+(&hE0-&h90)
        iOut += 1 : N += 1 :  :continue for
      end if
    end if
    #if __FB_DEBUG__    
      if sInput[N]>&h7F then puts("Warning: utf-8 char not converted!")
    #endif
    sOutput[iOut] = sInput[N] : iOut += 1
  next N
  return left(sOutput,iOut)
end function
#10
C / C++ / Re: chatbot Danny in C
Last post by ron77 - Sep 04, 2024, 05:17 PM
Okay, I made some final adjustments to the chatbot. First, let me clear that this chatbot is not politically correct. It is an offensive chatbot that is not suitable for minors under 18 years old, and also, I do not take on any responsibility for your usage of it. So here are the final elements of almost the final diversion of the chatbot in C programming Language.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdbool.h>
#include <unistd.h>

#define MAX_STRING_LENGTH 1000
#define MAX_ARRAY_SIZE 1000
#define MAX_KEYWORDS 20
#define MAX_REPLIES 50
#define MAX_MATCHES 10
#define MAX_SWAP_WORDS 100
#define MAX_MEMORY 15

char wordIn[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
char wordOut[MAX_SWAP_WORDS][MAX_STRING_LENGTH];
int wCnt = 0;

char memory[MAX_MEMORY][MAX_STRING_LENGTH];
int memoryCount = 0;

typedef struct {
    char keywords[MAX_KEYWORDS][MAX_STRING_LENGTH];
    char replies[MAX_REPLIES][MAX_STRING_LENGTH];
    int keywordCount;
    int replyCount;
} ArraySet;

ArraySet g_Key_Reply[MAX_ARRAY_SIZE];
int g_Key_ReplyCount = 0;

char default_replies[MAX_ARRAY_SIZE][MAX_STRING_LENGTH];
int default_reply_count = 0;

char* safe_strdup(const char* s) {
    if (!s) return NULL;
    char* result = strdup(s);
    if (!result) {
        fprintf(stderr, "Memory allocation failed in safe_strdup\n");
        exit(1);
    }
    return result;
}

char* isolatePunctuation(const char* s) {
    char* b = malloc(strlen(s) * 3 + 1);
    if (!b) return NULL;
    
    int j = 0;
    for (int i = 0; s[i]; i++) {
        if (strchr("?!,.:;<>(){}[]", s[i])) {
            b[j++] = ' ';
            b[j++] = s[i];
            b[j++] = ' ';
        } else {
            b[j++] = s[i];
        }
    }
    b[j] = '\0';
    return b;
}

void loadArrays(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    int currentSet = -1;
    
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = 0;  // Remove newline

        if (strncmp(line, "d1:", 3) == 0) {
            strcpy(default_replies[default_reply_count++], line + 3);
        }
    
        if (line[0] == 'k' && line[1] == ':') {
            if (currentSet == -1 || g_Key_Reply[currentSet].replyCount > 0) {
                currentSet++;
            }
            strcpy(g_Key_Reply[currentSet].keywords[g_Key_Reply[currentSet].keywordCount], line + 2);
            g_Key_Reply[currentSet].keywordCount++;
            g_Key_ReplyCount = currentSet + 1;
        } else if (line[0] == 'r' && line[1] == ':') {
            strcpy(g_Key_Reply[currentSet].replies[g_Key_Reply[currentSet].replyCount], line + 2);
            g_Key_Reply[currentSet].replyCount++;
        }
    }

    fclose(file);
	printf("number of keywords-replies pair groups %d\n", currentSet);
}

void loadSwapWords(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        printf("Error opening swap words file: %s\n", filename);
        return;
    }

    char line[MAX_STRING_LENGTH];
    while (fgets(line, sizeof(line), file) && wCnt < MAX_SWAP_WORDS) {
        line[strcspn(line, "\n")] = 0;  // Remove newline
        if (line[0] == 's' && line[1] == ':') {
            char* delimiter = strchr(line + 2, '>');
            if (delimiter) {
                *delimiter = '\0';
                strcpy(wordIn[wCnt], line + 2);
                strcpy(wordOut[wCnt], delimiter + 1);
                wCnt++;
            }
        }
    }

    fclose(file);
}

char* swapWords(const char* input) {
    if (!input) return NULL;
    char* result = safe_strdup(input);
    char* temp = malloc(strlen(input) * 2 + 1); // Allocate more space for worst-case scenario
    if (!temp) {
        free(result);
        return NULL;
    }

    char* word = strtok(result, " ");
    temp[0] = '\0';

    while (word != NULL) {
        bool swapped = false;
        for (int i = 0; i < wCnt; i++) {
            if (strcmp(word, wordIn[i]) == 0) {
                strcat(temp, wordOut[i]);
                strcat(temp, " ");
                swapped = true;
                break;
            }
        }
        if (!swapped) {
            strcat(temp, word);
            strcat(temp, " ");
        }
        word = strtok(NULL, " ");
    }

    // Remove trailing space
    int len = strlen(temp);
    if (len > 0 && temp[len - 1] == ' ') {
        temp[len - 1] = '\0';
    }

    free(result);
    return temp;
}

char* processReply(const char* reply, const char* userInput) {
    if (!reply || !userInput) return NULL;
    char* processedReply = safe_strdup(reply);
    int len = strlen(processedReply);
    
    if (len > 0 && processedReply[len - 1] == '*') {
        processedReply[len - 1] = '\0';  // Remove the asterisk
        
        // Save the user's input to memory
        if (memoryCount < MAX_MEMORY) {
            strncpy(memory[memoryCount], userInput, MAX_STRING_LENGTH - 1);
            memory[memoryCount][MAX_STRING_LENGTH - 1] = '\0';
            memoryCount++;
        }
        
        // Find the keyword in the user's input
        char* keyword = NULL;
        for (int i = 0; i < g_Key_ReplyCount; i++) {
            for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
                if (strstr(userInput, g_Key_Reply[i].keywords[j])) {
                    keyword = g_Key_Reply[i].keywords[j];
                    break;
                }
            }
            if (keyword) break;
        }
        
        if (keyword) {
            char* rest = strstr(userInput, keyword);
            if (rest) {
                rest += strlen(keyword);
                char* swapped = swapWords(rest);
                if (swapped) {
                    // Concatenate the swapped input to the reply
                    char* temp = malloc(strlen(processedReply) + strlen(swapped) + 2);
                    if (temp) {
                        sprintf(temp, "%s %s", processedReply, swapped);
                        free(processedReply);
                        processedReply = temp;
                    }
                    free(swapped);
                }
            }
        }
    }
    
    return processedReply;
}

char* userQuestion(const char* txt) {
    if (!txt) return NULL;
    char* matchedReplies[MAX_MATCHES] = {NULL};
    int matchCount = 0;
    bool found = false;
    char* combinedReply = NULL;

    for (int i = 0; i < g_Key_ReplyCount && matchCount < MAX_MATCHES; i++) {
        for (int j = 0; j < g_Key_Reply[i].keywordCount; j++) {
            if (strstr(txt, g_Key_Reply[i].keywords[j])) {
                int replyIndex = rand() % g_Key_Reply[i].replyCount;
                matchedReplies[matchCount] = safe_strdup(g_Key_Reply[i].replies[replyIndex]);
                matchCount++;
                found = true;
                break;
            }
        }
    }

    if (matchCount > 0) {
        size_t totalLength = 1;  // Start with 1 for the null terminator
        for (int i = 0; i < matchCount; i++) {
            char* processedReply = processReply(matchedReplies[i], txt);
            if (processedReply) {
                totalLength += strlen(processedReply) + 1;  // +1 for newline
                free(matchedReplies[i]);
                matchedReplies[i] = processedReply;
            }
        }

        combinedReply = malloc(totalLength);
        if (combinedReply) {
            combinedReply[0] = '\0';
            for (int i = 0; i < matchCount; i++) {
                if (matchedReplies[i]) {
                    strcat(combinedReply, matchedReplies[i]);
                    strcat(combinedReply, "\n");
                    free(matchedReplies[i]);
                }
            }
        }
    } else if (!found) {
        if (default_reply_count > 0) {
            int defaultIndex = rand() % default_reply_count;
            combinedReply = safe_strdup(default_replies[defaultIndex]);
        }
    }
    
    return combinedReply ? combinedReply : safe_strdup("I don't understand. Can you rephrase that?");
}

char* commands(char* txt) {
    char* isolated = isolatePunctuation(txt);
    for (int i = 0; isolated[i]; i++) {
        isolated[i] = tolower(isolated[i]);
    }
    
    char* response = userQuestion(isolated);
    
    free(isolated);
    return response;
}

void speak(const char* text) {
    char command[MAX_STRING_LENGTH * 2];
    snprintf(command, sizeof(command), "voice -r -1 -n \"Microsoft David Desktop\" \"%s\"", text);
    system(command);
}

int main() {
    srand(time(NULL));
    
    loadArrays("database.txt");
    loadSwapWords("swapwords.txt");
    
	printf("CHATBOT DANNY IN C PROGRAMMING LANGUAGE VERSION 1.1.6.5 (C) RON77\n");
	
    char input[MAX_STRING_LENGTH];
    char* response;
    
    while (1) {
        printf("> ");
        if (fgets(input, sizeof(input), stdin) == NULL) {
            break;
        }
        input[strcspn(input, "\n")] = 0;  // Remove newline
        
        if (strcmp(input, "quit") == 0) break;
        
        response = commands(input);
        
        if (response) {
            // Split the response into separate lines and speak each one
            char* line = strtok(response, "\n");
            while (line != NULL) {
                printf("%s\n", line);
                speak(line);
                line = strtok(NULL, "\n");
            }
            
            free(response);
        } else {
            printf("An error occurred while processing your input.\n");
        }
    }
    
    return 0;
}

You cannot view this attachment.

You cannot view this attachment.

this chatbot used 'voice.exe' TTS cli engine wrapper on windows...

https://elifulkerson.com/projects/commandline-text-to-speech.php