{
#### GameUI
#### Core functions for games with SDL Mixer
#### Copyright (c) 2016 Lucas Alexandre
#### Copyright (c)2004-2100, JEDI-SDL Team
}

unit GameUI;
{$R-}
interface
uses
classes, Console, SDL, SDL_Mixer, sound, sysUtils, windows;

type
PGObject = ^TGObject;
TGObject = record
name: string[25];
channel: integer;
sound: string[103];
PosicC: integer;
PosicL: integer;
volume: integer;
end;

var

{ Menu }

MenuItens: TStringList;
MenuItem: integer=0;

{ Music }

music: pMix_music;

{ Game objects }

objects: TList;
obj: integer;

{ Music routines }

function OpenMusic(filename: string): boolean;
procedure PlayMusic(loops: integer);
procedure MusicVolume(volume: integer);
procedure MusicFadeOut(value: integer);
procedure DiscardMusic;

{ Audio features }

function PlaySound(filename: string; loops: integer): boolean;
procedure waitSound(channel: integer);

{ Panning features }

procedure RefreshPanning(horizontal: integer; vertical: integer);

{ Game object management }

procedure AddObject(name: string);
procedure PlayObject(name: string; loops: integer);
procedure ObjectSound(name: string; sound: string);
procedure ObjectPosition(name: string; PosicC: integer; PosicL: integer);
procedure ObjectVolume(name: string; volume: integer);
function SearchObject(name: string): integer;
procedure DeleteObject(name: string);

{ Menu routines }

function RunMenu(c: char): integer;

{ Miscelaneous features }

procedure DelayGame(var count: integer);

implementation

var
chitem: pMix_Chunk;
chmenu: integer=0;

function OpenMusic(filename: string): boolean;
begin
OpenMusic:=false;
music:=Mix_LoadMus(pchar(filename));
if fileExists(filename) then
OpenMusic:=true;
end;

procedure PlayMusic(loops: integer);
begin
Mix_PlayMusic(music,loops);
end;

procedure MusicVolume(volume: integer);
begin
Mix_VolumeMusic(volume);
end;

function PlaySound(filename: string; loops: integer): boolean;
begin
PlaySound:=false;
play(filename,loops);
if fileExists(filename) then PlaySound:=true;
end;

procedure waitSound(channel: integer);
begin
while Mix_Playing(channel)<>0 do
begin
if keypressed then
if upcase(readkey)='F' then
begin
mix_HaltChannel(channel);
exit;
end;
sleep(1);
end;
mix_HaltChannel(channel);
end;

function Panning(ch: integer; ch1: integer; ch2: integer): boolean;
begin
Panning:=false;
if (ch1<0) or (ch2<0) then exit;
if (ch1>255) or (ch2>255) then exit;
if ch=0 then exit;
Panning:=true;
Mix_SetPanning(ch,ch1,ch2);
end;

procedure RefreshPanning(horizontal: integer; vertical: integer);
var i: integer;
pan,pan2: integer;
volume: integer;
vpan: integer;
begin
if objects.Count=0 then exit;
for i:=0 to objects.Count-1 do
begin
volume:=128;
vpan:=abs(Vertical-PGObject(objects[i])^.PosicL);
if vpan<16 then
begin
volume:=128;
vpan:=abs(Vertical-PGObject(objects[i])^.PosicL);
ObjectVolume(PGObject(objects[i])^.name,volume-vpan*8);
volume:=volume-vpan*8;
PGObject(objects[i])^.volume:=volume;
end
else
ObjectVolume(PGObject(objects[i])^.name,0);

if (vpan=0) or (vertical=128) then
ObjectVolume(PGObject(objects[i])^.name,128);

pan:=PGObject(objects[i])^.PosicC;
pan2:=pan;
pan:=abs(horizontal-pan2);

 if (pan=0) then
 begin
 Mix_SetPanning(PGObject(objects[i])^.channel,255,255);
Continue;
 end;

if pan>16 then
begin
Mix_SetPanning(PGObject(objects[i])^.channel,0,0);
Continue;
end;

if pan<16 then
begin

if (horizontal<pan2) then
Mix_SetPanning(PGObject(objects[i])^.channel,255-pan*15,255)
else
Mix_SetPanning(PGObject(objects[i])^.channel,255,255-10-pan*15);

end;
end;
end;

procedure AddObject(name: string);
var
data: PGObject;
begin
new(data);
data^.name:=Name;
data^.volume:=128;
Objects.Add(data);
end;

procedure ObjectVolume(name: string; volume: integer);
var i: integer;
begin
i:=SearchObject(name);
if (volume<0) or (volume>128) then exit;
PGObject(objects[i])^.volume:=volume;
Mix_Volume(PGObject(objects[i])^.channel,volume);
end;

function SearchObject(name: string): integer;
var i: integer;
begin
try
i:=-1;
for i:=0 to objects.Count-1 do
if PGObject(objects[i])^.Name=Name then
SearchObject:=i;
if objects.Count-1=0 then SearchObject:=0;
Except
end;
end;

procedure DeleteObject(name: string);
var i: integer;
begin
i:=SearchObject(name);
if i=-1 then exit;
Mix_HaltChannel(PGObject(objects[i])^.channel);
objects.Delete(i);
end;

procedure PlayObject(name: string; loops: integer);
var o: integer;
begin
o:=SearchObject(Name);
PGObject(objects[o])^.channel:=play(PGObject(objects[o])^.sound,loops);
end;

procedure ObjectSound(name: string; sound: string);
var o: integer;
begin
o:=SearchObject(name);
PGObject(objects[o])^.sound:=sound;
end;

procedure MusicFadeOut(value: integer);
begin
Mix_FadeOutMusic(value);
end;

procedure DiscardMusic;
begin
Mix_PauseMusic;
Mix_FreeMusic(music);
end;

procedure ObjectPosition(name: string; PosicC: integer; PosicL: integer);
var i: integer;
begin
i:=SearchObject(name);
PGObject(objects[i])^.PosicC:=PosicC;
PGObject(objects[i])^.PosicL:=PosicL;
end;

function RunMenu(c: char): integer;
procedure PlayItem;
begin
if fileExists('Sounds\Dialogos\'+menuItens[menuItem]) then
WaitSound(play('Dialogos\'+menuItens[menuItem],0));
end;
begin
case c of
#13: begin
RunMenu:=MenuItem;
exit;
end;
#72: dec(MenuItem);
#80: inc(MenuItem);
end;
if (MenuItem>MenuItens.Count-1) or (MenuItem<0) then
begin
Mix_HaltChannel(chmenu);
chmenu:=play('Dialogos\menu_error.wav',0);
if MenuItem>MenuItens.Count-1 then MenuItem:=MenuItens.Count-1;
if MenuItem<0 then MenuItem:=0;
PlayItem;
exit;
end;
Mix_HaltChannel(chmenu);
chmenu:=play('Dialogos\Menu_Select.wav',0);
PlayItem;
while mix_playing(chmenu)<>0 do
if keypressed then mix_haltchannel(chmenu);
RunMenu:=MenuItem;
end;

procedure DelayGame(var count: integer);
begin
sleep(1); inc(count);
end;

begin
objects:=TList.Create;
end.
