AlphaHost

by James Hall: L6 Age ~17

The AlphaHost Program

program AlphaHost;
{
    Copyright (c) 2011 James Hall

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/
}
  {$r+}
uses
  SDL, math, SDL_mixer, sdl_ttf, strutils, classes, Sysutils, sdl_net;
type
  Tinput = record
    left, right, up, down, space, enter, mousedown, Mouseup : boolean;
  end;

type
  Tclient = record
    live : boolean;
    csocket :  ptcpsocket;
    name : string;
    x, y : integer;
  end;

var
  Image, backgroundimage, display : Psdl_surface;
  Filename : PChar = 'images/koala.bmp';
  Filename2 : PChar = 'images/background.bmp';
  Filename6 : PChar = 'sounds/mariogalaxy2.mp3';
  Filename8 : PChar = 'sounds/laugh.wav';
  MyEvent : TSDL_Event;
  gameinput : Tinput;
  mousex, mousey, i, j, numlive : Uint32;
  music : pMIX_MUSIC = nil;
  slaugh : pMIX_CHUNK = nil;
  soundchannel : integer;
  fontcolour1, fontcolour2 : psdl_color;
  loadedfont : pointer;
  Ipaddress : TIPaddress;
  socket : ptcpsocket;
  wait : boolean;
  tempstr, resstr : string;
  SocketSet: PSDLNet_SocketSet;
  clients : array[1 .. 20] of Tclient;
  numclients, lowspace : integer;
{const
  AUDIO_FREQUENCY : INTEGER = 22050;
  AUDIO_FORMAT : WORD = AUDIO_S16;
  AUDIO_CHANNELS : INTEGER = 2;
  AUDIO_CHUNKSIZE : INTEGER = 4096;}

procedure closeall;
begin
  sdlnet_tcp_close(socket);
  SDLNet_FreeSocketSet(SocketSet);
  SDL_ShowCursor(SDL_ENABLE);
  SDL_Freesurface(Image);
  SDL_Freesurface(BackgroundImage);
  {MIX_HALTMUSIC;
  MIX_HALTCHANNEL(soundchannel);
  MIX_FREEMUSIC(music);
  MIX_FREECHUNK(slaugh);
  MIX_CLOSEAUDIO;}
  DISPOSE(fontcolour1);
  DISPOSE(fontcolour2);
  TTF_CLOSEFONT(loadedfont);
  TTF_QUIT;
  sdlnet_quit;
  SDL_Quit;
  halt;
end;

procedure checkinput;
begin
  while SDL_PollEvent(@MyEvent) > 0 do
    begin
      if MyEvent.type_ = SDL_mousemotion then
        begin
          mousex := Myevent.motion.x;
          mousey := Myevent.motion.y;
        end;
      if MyEvent.type_ = SDL_mousebuttondown then
        begin
          gameinput.mousedown := true;
        end;
      if MyEvent.type_ = SDL_mousebuttonup then
        begin
          gameinput.mousedown := false;
        end;
      if MyEvent.type_ = SDL_KeyDown then //Trailing underscore because type is a keyword
        begin
          case MyEvent.key.keysym.sym of
            SDLK_ESCAPE : closeall;
            SDLK_a      : gameinput.left := true;
            SDLK_w      : gameinput.up := true;
            SDLK_s      : gameinput.down := true;
            SDLK_d      : gameinput.right := true;
            SDLK_SPACE  : gameinput.space := true;
            SDLK_return : gameinput.enter := true;
          end;
        end;
      if MyEvent.type_ = SDL_KeyUp then //Trailing underscore because type is a keyword
        begin
          case MyEvent.key.keysym.sym of
            SDLK_a      : gameinput.left := false;
            SDLK_w      : gameinput.up := false;
            SDLK_s      : gameinput.down := false;
            SDLK_d      : gameinput.right := false;
            SDLK_SPACE  : gameinput.space := false;
            SDLK_return : gameinput.enter := false;
          end;
        end;
    end;
end;

function ReceivefromSocket(num : integer; Socket: PTCPSocket): string;
const
  MAX_TIMEOUT = 10;
var
  i, strlen : integer;
  jagstr, leftjagstr, resstr : string;
begin
  Result := '';
  try
    jagstr := 'aaaaaaaa';
    resstr := '';
    if SDLNet_CheckSockets(SocketSet, MAX_TIMEOUT) > 0 then
      begin
        if not SDLNet_SocketReady(PSDLNet_GenericSocket(Socket)) then
          Exit;
        if SDLNet_TCP_Recv(Socket, @jagstr + 1, 8) < 1 then
          begin
            clients[num].live := false;
            Exit;
          end;
        leftjagstr := leftstr(jagstr, 4);
        if leftjagstr = 'nstr' then   //code for name
          begin
            strlen := strtoint(rightstr(jagstr, 4));
            for i := 1 to strlen do
              resstr := resstr + 'x';
            SDLNet_TCP_Recv(Socket, @resstr + 1, strlen);
            result := 'ming';
            writeln(resstr);
            clients[num].name := resstr;
            resstr := 'pliv';
            //1 digit
            if num < 10 then
              resstr := resstr + '0';
            resstr := resstr + inttostr(num);
            if length(clients[num].name) < 10 then
              resstr := resstr + '0';
            resstr := resstr + inttostr(length(clients[num].name));
            resstr := resstr + clients[num].name;
            for i := 1 to 20 do
              if clients[i].live then
                begin
                  sdlnet_tcp_send(clients[i].csocket, @resstr + 1, 8 + length(clients[num].name));
                end;
           end;

        if leftjagstr = 'xstr' then
          begin
            strlen := strtoint(rightstr(jagstr, 4));
            for i := 1 to strlen do
              resstr := resstr + 'x';
            SDLNet_TCP_Recv(Socket, @resstr + 1, strlen);
            result := resstr;
            if resstr <> '' then
              writeln(clients[num].name, ' says: ', resstr);
          end;

        if leftjagstr = 'pdet' then
          begin
            clients[num].x := 0;
            clients[num].y := 0;
            tempstr := 'aaaa';
            SDLNet_TCP_Recv(Socket, @tempstr + 1, 4);
            clients[num].x := strtoint(tempstr);
            SDLNet_TCP_Recv(Socket, @tempstr + 1, 4);
            clients[num].y := strtoint(tempstr);
            result := 'd';
          end;
        exit;
    end;
  finally
  end;
end;

procedure newlow;
begin
  repeat
    inc(lowspace);
  until clients[lowspace].live = false;
end;

procedure sendcordstolivesockets(clientnum : integer);
//Send co-ordinate code (beginning with pcor) then send co-ordinates as a string
var
  tempstr, str: string;
  i : integer;
begin
  str := inttostr(numlive);
  tempstr := '';
  for i := 1 to 4 - length(inttostr(length(str))) do
    tempstr := '0' + tempstr;
  tempstr := 'pcor' + tempstr + str;
  for i := 1 to 20 do
    if clients[i].live then
      tempstr := tempstr + rightstr(inttostr(100000000 + 1000000 * i + 1000 * clients[i].x + clients[i].y), 8);
  for i := 1 to 20 do
    if clients[i].live then
      begin
        sdlnet_tcp_send(clients[i].csocket, @tempstr + 1, 8 * numlive + 8);
      end;
end;

begin
  Image := SDL_LoadBMP(Filename);
  BackgroundImage := SDL_LoadBMP(Filename2);
  //initialise video
  SDL_Init(SDL_INIT_VIDEO);
  Display := SDL_SetVideoMode(BackgroundImage^.w, BackgroundImage^.h, 24, SDL_HWSURFACE or SDL_DOUBLEBUF);
  SDL_WM_SetCaption('Host', nil);
  SDL_ShowCursor(SDL_ENABLE);
  {//Initialise audio
  SDL_Init(SDL_INIT_AUDIO);
  IF MIX_OPENAUDIO(AUDIO_FREQUENCY, AUDIO_FORMAT, AUDIO_CHANNELS, AUDIO_CHUNKSIZE)<>0 THEN HALT;
  music:=MIX_LOADMUS(filename6);
  MIX_VOLUMEMUSIC(20);
  slaugh:=MIX_LOADWAV(filename8);
  MIX_VOLUMECHUNK(slaugh,10);
  //music start (can't be a host without good music)
  MIX_PLAYMUSIC(music,-1); //-1 = infinite, 0 = once, 1 = twice,...   Starting the music}
  //network
  //init holders
  for i := 1 to 20 do
    with clients[i] do
      begin
        live := false;
        name := 'Bruce';
        x := 100;
        y := 100;
      end;
  numclients := 0;
  lowspace := 1;
  numlive := 0;

  sdlnet_init;
  if SDLNet_ResolveHost(IPAddress, nil, 1479) <> 0 then
    closeall;
  writeln('Enter 127.0.0.1 for local host to run client and host on same computer');
  Socket := SDLNet_TCP_Open(IPAddress);
  if socket = nil then
    closeall;
  wait := true;
  writeln('waiting');
  SocketSet := SDLNet_AllocSocketSet(20);
  //Main loop
  repeat
    //Inputs
    checkinput;
    //network
    clients[lowspace].csocket := sdlnet_tcp_accept(socket);
    if clients[lowspace].csocket <> nil then
      begin
        for i := 1 to 20 do
          if clients[i].live then
            begin
              resstr := 'pliv';
              if i < 10 then
                resstr := resstr + '0';
              resstr := resstr + inttostr(i);
              if length(clients[i].name) < 10 then
                resstr := resstr + '0';
              resstr := resstr + inttostr(length(clients[i].name));
              resstr := resstr + clients[i].name;
              sdlnet_tcp_send(clients[lowspace].csocket, @resstr + 1, 8 + length(clients[i].name));
            end;
        clients[lowspace].live := true;
        clients[lowspace].name := 'NA';
        clients[lowspace].x := 100;
        clients[lowspace].y := 100;
        writeln('connected: ', lowspace);
        SDLNet_TCP_AddSocket(SocketSet, clients[lowspace].csocket);
        inc(numlive);
        newlow;
      end;

    for i := 1 to 20 do
      with clients[i] do
        if live then
          begin
            tempstr := receivefromsocket(i, csocket);
            if (tempstr = 'exit') or (live = false) then
              begin
                live := false;
                if i < lowspace then
                  lowspace := i;
                SDLNet_TCP_DelSocket(SocketSet, csocket);
                sdlnet_tcp_close(csocket);
                writeln('disconnected: ', clients[i].name);
                dec(numlive);
                resstr := 'pdis';  //code for player disconnected
                if i < 10 then
                  resstr := resstr + '0';
                resstr := resstr + '00' + inttostr(i);
                for j := 1 to 20 do
                  if clients[j].live then
                    begin
                      sdlnet_tcp_send(clients[j].csocket, @resstr + 1, 8);
                    end;
              end;
          end;

    sendcordstolivesockets(i);  //CHECK LOOP
       { mix_haltmusic;
         mix_playmusic(gameovermusic,-1); //Starting the ending music   }
    //wait 30 milliseconds
   SDL_Delay(30);
  until 1 = 2;
end.

Remarks

Could you write your own client and server programs using SDL?

Programming - a skill for life!

by James Hall: L6 Age ~17