diff --git a/BearURQ.dproj b/BearURQ.dproj index 2a5f8d4..8337238 100644 --- a/BearURQ.dproj +++ b/BearURQ.dproj @@ -96,6 +96,9 @@ -d quests\test.qst + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + (None) @@ -132,6 +135,10 @@ BearURQ.dpr + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + False diff --git a/quests/inc.qst b/quests/inc.qst deleted file mode 100644 index 43b6396..0000000 --- a/quests/inc.qst +++ /dev/null @@ -1,4 +0,0 @@ -:loc3 - pln Test 3 - btn loc1, 1 -end \ No newline at end of file diff --git a/quests/inc1.qst b/quests/inc1.qst new file mode 100644 index 0000000..0ff3115 --- /dev/null +++ b/quests/inc1.qst @@ -0,0 +1,8 @@ +; + +:loc3 + pln Test 3 + btn loc1, Назад +end + +include inc2.qst \ No newline at end of file diff --git a/quests/test.qst b/quests/test.qst index 2983d0b..1433f87 100644 --- a/quests/test.qst +++ b/quests/test.qst @@ -1,17 +1,25 @@ - - -:loc1 +; +gametitle = "serg" +; + :loc1 + a =(2+2)*2+1 + p 123 + p 456 + p 789 + pln hhhh pln Test 1 - btn loc2, 2 - btn loc3, 3 -end + pln Значение переменной А: #a$ + btn loc2, Локация 2 + btn loc3, Локация 3 + btn loc4, Локация 4 + end -:loc2 + :loc2 pln Test 2 - btn loc1, -end + btn loc1, Назад + end -include inc.qst +include inc1.qst diff --git a/sources/BearURQ.Engine.pas b/sources/BearURQ.Engine.pas index a6ad8d2..ef86520 100644 --- a/sources/BearURQ.Engine.pas +++ b/sources/BearURQ.Engine.pas @@ -12,6 +12,10 @@ interface type TEngine = class(TObject) + private type + IfResult = record + If1, If2, If3, If4: string; + end; private FLocCount: Integer; FTerminal: TTerminal; @@ -19,7 +23,15 @@ TEngine = class(TObject) FButtons: TButtons; FVars: TVars; FQuest: TQuest; + function LoadFromFile(const AFileName: string; DefCode: string) + : string; overload; + procedure ReplaceVars(var Code: string); + function GetCode(Code: string): string; + function GetLeksemsFromString(Text: String): TStringList; + function GetIf(S: string): IfResult; + procedure GetVars(A, B: string; Id: Integer = 0); public + FIsClick: Boolean; // Щелчек, выбор локации FIsGoTo: Boolean; // Для перехода по GoTo FirstText: Boolean; // Новый текст FLocBtnCnt: Byte; // Счетчик кнопок на локации @@ -35,10 +47,8 @@ TEngine = class(TObject) property Quest: TQuest read FQuest write FQuest; procedure Clear; procedure LoadFromFile(const AFileName: string); overload; - function LoadFromFile(const AFileName: string; DefCode: string) - : string; overload; procedure GoToLocation(const ALocName: string); - procedure Run(const ACode: string); + procedure RunCode(const ACode: string); end; implementation @@ -46,7 +56,8 @@ implementation uses SysUtils, Vcl.Dialogs, - BearURQ.Utils; + BearURQ.Utils, + BearURQ.Math; { TEngine } @@ -82,40 +93,239 @@ destructor TEngine.Destroy; end; // Переход на метку локации +function TEngine.GetCode(Code: string): string; +var + I, J, V1, U: Integer; + SS, LX, LT, LR, LL: String; + HF: TSplitResult; + LS: TStringList; + B: Boolean; +begin + // Выполнить инструкции URQL и вернуть результат + B := False; + // Строковые переменные + if (Code[1] = '%') then + begin + // Это точно строка + Delete(Code, 1, 1); + // Конкатенация строк + // Загружаем список лексем + LS := GetLeksemsFromString(Code); + Code := ''; + // Перебираем лексемы и склеиваем строки + SS := ''; + for I := 0 to LS.Count - 1 do + if not Math.IsDelimiter(LS[I]) then + if Vars.IsVar(LS[I]) then + SS := SS + Vars.GetVarValue(LS[I], '') + else + SS := SS + LS[I]; + if (SS = '0') then + SS := ''; + ReplaceVars(SS); + Result := SS; + Exit; + end; + + // Использовать текстовые переменные в кавычках без instr + if (Code[1] = '"') then + begin + SS := ''; + HF := Explode('+', Code); + for I := 0 to High(HF) do + begin + LL := Trim(HF[I]); + Delete(LL, 1, 1); + J := Length(LL); + Delete(LL, J, J); + SS := SS + LL; + end; + ReplaceVars(SS); + Result := SS; + Exit; + end; + + // Приводим код к удобному выражению + LS := TStringList.Create; + // Загружаем список лексем + LS := GetLeksemsFromString(Code); + Code := ''; + for I := 0 to LS.Count - 1 do + // Если лексема не число ... + if not Math.IsNumber(LS[I]) + // ... и не символ ... + and not Math.IsDelimiter(LS[I]) + // ... и не функция ... + and not Math.IsFunction(LS[I]) then + begin + // Возможно это функция URQL RAND? + LS[I] := AdvLowerCase(LS[I]); + if (Copy(LS[I], 1, 3) = 'rnd') then + begin + LS[I] := Trim(Copy(LS[I], 4, Length(LS[I]))); + U := StrToIntDef(LS[I], 0); + Randomize; + LS[I] := IntToStr(Random(U) + 1) + end + else // Это переменная + // Отмечаем, что это строковая переменная + if not Math.IsNumber(Vars.GetVarValue(LS[I], '')) then + B := True; + // Конкатенация строк + if not Vars.IsVar(LS[I]) then + if (Trim(LS[I]) <> '') then + Continue; + // Заменяем переменные их значениями + LS[I] := Vars.GetVarValue(LS[I], ''); + end; + + // Заполняем измененную строку для интерпретации выражения + for I := 0 to LS.Count - 1 do + Code := Code + LS[I]; + LS.Free; + Result := Code; + // Результат для строк + if B then + begin + Result := StrReplace(Code, '+', ''); + Result := StrReplace(Result, '"', ''); + ReplaceVars(Result); + // Exit; + end; +end; + +function TEngine.GetIf(S: string): IfResult; +var + Z: array [0 .. 5] of string; + E: TSplitResult; + I: Byte; + K: String; + C: Integer; +begin + Result.If1 := ''; + Result.If2 := ''; + Result.If3 := ''; + Result.If4 := ''; + if (Pos('not ', S) > 0) then + Result.If4 := 'NOT'; + S := StrReplace(S, 'not ', ''); + Z[0] := '<>'; + Z[1] := '>='; + Z[2] := '<='; + Z[3] := '='; + Z[4] := '>'; + Z[5] := '<'; + // Условия + for I := 0 to High(Z) do + if (Pos(Z[I], S) > 0) then + begin + E := Explode(Z[I], S); + Result.If1 := Trim(E[0]); + Result.If2 := Z[I]; + Result.If3 := Trim(E[1]); + Exit; + end; + // Условия для предметов + E := Explode(',', S); + K := Trim(E[0]); + if High(E) > 0 then + C := StrToIntDef(E[1], 1) + else + C := 1; + Result.If1 := K; + Result.If2 := '#'; + Result.If3 := IntToStr(C); +end; + +function TEngine.GetLeksemsFromString(Text: String): TStringList; +var + I, P: Integer; + S: string; + + procedure AddLexem(F: string); + begin + if (F <> '') then + begin + Result.Append(F); + S := ''; + end; + end; + +begin + S := ''; + P := 0; + Result := TStringList.Create; + for I := 1 to Length(Text) do + begin + if (Text[I] in [' ', '&', '=', '+', '-', '*', '/', '^', '(', ')', '<', '>', + '#', '%', '$', '{', '}', '"']) then + begin + AddLexem(S); + AddLexem(Text[I]); + Continue; + end; + S := S + Text[I]; + end; + AddLexem(S); +end; + +procedure TEngine.GetVars(A, B: string; Id: Integer); +var + E: TSplitResult; + I, X: Integer; + H: string; +begin + E := Explode(',', A); + for I := 0 to High(E) do + begin + H := Trim(E[I]); + Vars.SetVarValue(H, B); + end; +end; + procedure TEngine.GoToLocation(const ALocName: string); var CurrLocName: string; - I, A, C, CurLocCount: Integer; - B: Boolean; + I, CurrLocIndex: Integer; // Нач. индекс тек. локации + CommLocIndex: Integer; // Нач. индекс локации COMMON + CurrLocCount: Integer; // Счетчик заходов на тек. локацию SL: TStringList; begin CurrLocName := AdvLowerCase(Trim(ALocName)); if (CurrLocName = '') then - A := 0 + CurrLocIndex := 0 else - A := FQuestList.IndexOf(':' + CurrLocName); - if (A < 0) then + CurrLocIndex := FQuestList.IndexOf(':' + CurrLocName); + if (CurrLocIndex < 0) then Exit; // Счетчик заходов на локацию - CurLocCount := Vars.GetVarValue('count_' + CurrLocName, 0); - Vars.SetVarValue('count_' + CurrLocName, CurLocCount + 1); + CurrLocCount := Vars.GetVarValue('count_' + CurrLocName, 0); + Vars.SetVarValue('count_' + CurrLocName, CurrLocCount + 1); // SL := TStringList.Create; try // Грузим локацию COMMON - + if FIsClick then + begin + FIsClick := False; + CommLocIndex := FQuestList.IndexOf(':common'); + if (CommLocIndex >= 0) then + for I := CommLocIndex to FQuestList.Count - 1 do + begin + if CompText(FQuestList[I], 'end') then + Break; + SL.Append(FQuestList[I]); + end; + RunCode(SL.Text); + FIsGoTo := False; + end; // Грузим текущую локацию SL.Clear; - for I := A to FQuestList.Count - 1 do + for I := CurrLocIndex to FQuestList.Count - 1 do begin - try - // if ((FQuestList[I][1] = 'e') or (FQuestList[I][1] = 'E')) and - // ((FQuestList[I][2] = 'n') or (FQuestList[I][2] = 'N')) and - // ((FQuestList[I][3] = 'd') or (FQuestList[I][3] = 'D')) then - // Break; - SL.Append(FQuestList[I]); - except - end; + if CompText(FQuestList[I], 'end') then + Break; + SL.Append(FQuestList[I]); end; // Удаляем все метки внутри локации for I := SL.Count - 1 downto 0 do @@ -124,7 +334,7 @@ procedure TEngine.GoToLocation(const ALocName: string); // Сохраняем имя текущей локации в переменной Vars.SetVarValue('location', CurrLocName); // Выполняем комманды - Run(SL.Text); + RunCode(SL.Text); FIsGoTo := False; finally SL.Free; @@ -134,7 +344,7 @@ procedure TEngine.GoToLocation(const ALocName: string); // Загрузить квест из файла procedure TEngine.LoadFromFile(const AFileName: string); var - I, J, A, B, C: Integer; + I, J, B, C: Integer; SL: array [1 .. 3] of TStringList; F: string; label BR; @@ -142,10 +352,11 @@ procedure TEngine.LoadFromFile(const AFileName: string); // Текущий квест FQuestFileName := Trim(AFileName); // Путь к папке квеста - Vars.SetVarValue('quest_path', ExtractFilePath(FQuestFileName)); + Vars.SetVarValue('quest_path', ExtractFilePath(ParamStr(0)) + FQuestFileName); Vars.SetVarValue('previous_loc', ''); FLocCount := 0; FIsGoTo := False; + FIsClick := False; FQuestList.Clear; FQuestList.Text := LoadFromFile(FQuestFileName, ''); // Вставки Include @@ -155,17 +366,19 @@ procedure TEngine.LoadFromFile(const AFileName: string); BR: // Начало проверки на наличие вставок Include for I := 0 to FQuestList.Count - 1 do begin - if Copy(FQuestList[I], 1, 7) = 'include' then + if CompText(FQuestList[I], 'include') then begin for J := 1 to 3 do SL[J].Clear; - for B := 0 to I - 1 do SL[1].Append(FQuestList[B]); F := Trim(Copy(FQuestList[I], 8, Length(FQuestList[I]))); - SL[2].Text := LoadFromFile(ExtractFilePath(FQuestFileName) + F, ''); + SL[2].Text := LoadFromFile(ExtractFilePath(ParamStr(0)) + + ExtractFilePath(FQuestFileName) + F, ''); for C := I + 1 to FQuestList.Count - 1 do SL[3].Append(FQuestList[C]); + // Добавляем код инклюда в код квеста и проверяем снова код + // на наличие инклюдов FQuestList.Text := SL[1].Text + SL[2].Text + SL[3].Text; GoTo BR; Break; @@ -198,7 +411,7 @@ function TEngine.LoadFromFile(const AFileName: string; DefCode: string): string; try if FileExists(AFileName) then begin - SL.LoadFromFile(AFileName); + SL.LoadFromFile(AFileName, TEncoding.UTF8); // Многострочный комментарий /* */ T := SL.Text; L := Length(T); @@ -243,9 +456,328 @@ function TEngine.LoadFromFile(const AFileName: string; DefCode: string): string; end; // Разбор кода -procedure TEngine.Run(const ACode: string); +procedure TEngine.ReplaceVars(var Code: string); +var + I, L, P1, P2: Integer; + S, F: string; + AddTextFlag: Boolean; begin - ShowMessage(ACode); + // Подстановки + // Пробел + Code := StrReplace(Code, '#$', ' '); + // Выполняем комманды в подстановках + AddTextFlag := False; + S := ''; + F := Code; + L := Length(F); + Code := ''; + if (L > 0) then + for I := 1 to L do + begin + if AddTextFlag then + begin + if F[I] = '$' then + begin + Code := Code + GetCode(S); + AddTextFlag := False; + S := ''; + Continue; + end; + S := S + F[I]; + end + else if (F[I] <> '#') or (F[I + 1] = '/') then + Code := Code + F[I] + else + AddTextFlag := True; + end; +end; + +procedure TEngine.RunCode(const ACode: string); +var + I, P, J, D, C, L, N, U, SR, AP: Integer; + A, G, S, CS, K, V, R, LX, LT, LR, E1, E2, F1, TU, SS, LL: string; + E, H, W, B, M, T, HF: TSplitResult; + DoOrCnt, DoCnt: Byte; + F: IfResult; + V1, V2, V3: Integer; + Z: TStringList; +begin + if (ACode = '') then + Exit; + Z := TStringList.Create; + try + try + Z.Text := ACode; + for I := 0 to Z.Count - 1 do + begin + // Если это был GOTO, то пропускаются все комманды после него + if FIsGoTo then + Continue; + S := Trim(Z[I]); + if (Copy(S, 1, 3) <> 'if ') then + if (Pos('&', S) > 0) then + begin + H := Explode('&', S); + for U := 0 to High(H) do + if not FExitFlag then + RunCode(Trim(H[U])); + Continue; + end; + // Выход из вложенности операторами quit и end + if FExitFlag then + Exit; + { + if (Copy(S, 1, 3) = 'inv') then + begin + U := 1; + while (U < Length(V)) do + begin + if (S[U] = '+') or (S[U] = '-') then begin Inc(U, 2); Continue; end; + if (S[U] = ' ') then Delete(S, U, 1) else Inc(U); + end; + end; + } + P := Pos(' ', S); + if (P <= 0) then + P := Length(S); + K := AdvLowerCase(Trim(Copy(S, 1, P))); + V := Copy(S, P + 1, Length(S)); + begin + { // TextAlign + case Vars.GIVar('textalign') of + 3: + TextAlign := 1; + else + TextAlign := 0; + end; } + // Sellect + if (K = 'quit') or (K = 'end') then + begin + FExitFlag := True; + Exit; + end + else if (K = 'perkill') then + Vars.Clear + else if (K = 'invkill') then + // Inv.Clear + else if (K = 'cls') then + begin + // Очистить экран + Location.Clear; + Buttons.Clear; + FirstText := True; + end + else + // PROC и GOTO не выполняют COMMON! + if (K = 'proc') then + begin + GoToLocation(Trim(V)); + FIsGoTo := False; + end + else if (K = 'goto') then + begin + GoToLocation(Trim(V)); + FIsGoTo := True; + end + else if (K = 'p') or (K = 'print') then + begin + ReplaceVars(V); + E := Explode('#/$', V); + if (High(E) >= 0) then + for U := 0 to High(E) do + Location.Append(E[U]); + end + else if (K = 'pln') or (K = 'println') then + begin + ReplaceVars(V); + E := Explode('#/$', V); + if (High(E) >= 0) then + for U := 0 to High(E) do + begin + Location.Append(E[U]); + Location.Append(#13#10); + end; + end + else + // Кнопки + if (K = 'btn') then + begin + ReplaceVars(V); + E := Explode(',', V); + R := E[1]; + if (High(E) > 1) then + for U := 2 to High(E) do + R := R + ',' + E[U]; + // Добавляем кнопку в список + Buttons.Append(Trim(E[0]), Trim(R)); + end + else + // Записываем текст в переменные + if (K = 'instr') then + begin + ReplaceVars(V); + E := Explode('=', V); + GetVars(E[0], E[1]); + end + else + // Конструкция IF + if (K = 'if') then + begin + // if Pos(' then ', V) <= 0 then + // ShowMessage('После IF oтсутствует оператор THEN!'); + A := Trim(GetINIKey(V, 'then')); + G := Trim(GetINIValue(V, 'then')); + E1 := Trim(GetINIKey(G, 'else')); + E2 := Trim(GetINIValue(G, 'else')); + DoOrCnt := 0; + V := Trim(A); + T := Explode(' or ', V); + for N := 0 to High(T) do + begin + DoCnt := 0; + B := Explode(' and ', T[N]); + for J := 0 to High(B) do + begin + F := GetIf(Trim(B[J])); + // Разбор условий + if Vars.IsVar(F.If3) then + F.If3 := Vars.GetVarValue(F.If3, ''); + if (F.If4 = '') then + begin + if (F.If2 = '<>') then + if (Vars.GetVarValue(F.If1, 0) <> + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '>=') then + if (Vars.GetVarValue(F.If1, 0) >= + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '<=') then + if (Vars.GetVarValue(F.If1, 0) <= + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '=') then + if (Vars.GetVarValue(F.If1, 0) + = StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '>') then + if (Vars.GetVarValue(F.If1, 0) > + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '<') then + if (Vars.GetVarValue(F.If1, 0) < + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + end + else + begin + // NOT! + if (F.If2 = '<>') then + if not(Vars.GetVarValue(F.If1, 0) <> + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '>=') then + if not(Vars.GetVarValue(F.If1, 0) >= + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '<=') then + if not(Vars.GetVarValue(F.If1, 0) <= + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '=') then + if not(Vars.GetVarValue(F.If1, 0) + = StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '>') then + if not(Vars.GetVarValue(F.If1, 0) > + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + if (F.If2 = '<') then + if not(Vars.GetVarValue(F.If1, 0) < + StrToIntDef(F.If3, 0)) then + Inc(DoCnt); + end; + // Предметы в условиях + if (F.If2 = '#') then + begin + // Снача приводим к обычному виду форму типа "30 семян" + F1 := F.If1; + if Math.IsNumber(F1[1]) then + begin + SR := Pos(' ', F1); + F.If3 := Trim(Copy(F1, 1, SR)); + F.If1 := Trim(Copy(F1, SR + 1, Length(F1))); + end; + // + { if ((F.If4 = '') and + (Inv.IsItem(F.If1, StrToInt(F.If3)))) or + ((F.If4 = 'NOT') and + (not Inv.IsItem(F.If1, StrToInt(F.If3)))) then + Inc(DoCnt); } + end; + end; + // DO IF .. THEN .. ELSE .. + if (DoCnt - 1 = High(B)) then + begin + if (E1 <> '') then + RunCode(E1); + end + else + begin + if (E2 <> '') then + RunCode(E2); + end; + end; + end + else + // Inventory + if ((K = 'inv+') or (K = 'inv-')) then + begin + ReplaceVars(V); + if Pos(',', V) <= 0 then + begin + R := V; + C := 1; + end + else + begin + R := Trim(GetINIValue(V, ',', '')); + C := StrToIntDef(GetINIKey(V, ','), 1); + end; + if (C < 1) then + C := 1; + if (K = 'inv+') and (R <> '') then + // Inv.Add(R, C) + else if (K = 'inv-') and (R <> '') then + // Inv.Del(R, C); + end + else + // Записываем данные в переменные + //if (Pos('=', S) > 0) then + begin + //E := Explode('=', S); + //R := Trim(E[1]); + //ShowMessage(E[0]); + //GetVars(Trim(E[0]), GetCode(R)); + { // Считываем значения переменных инвентаря и перезаписываем их новое значение + for U := 0 to Vars.Count - 1 do + if (Copy(Trim(Vars.FID[U]), 1, 4) = 'inv_') then + begin + R := Trim(Copy(Trim(Vars.FID[U]), 5, + Length(Vars.FID[U]))); + Inv.Let(R, StrToIntDef(Vars.FValue[U], 0)); + end; } + end; + end; // IF + end; + finally + Z.Free; + end; + // Сохраняем в переменную количество слотов в инвентаре + // Vars.SetVarValue('urq_inv', Inv.Count); + // Vars.SaveToFile('vars.txt'); // Тест + except + end; end; end. diff --git a/sources/BearURQ.Location.pas b/sources/BearURQ.Location.pas index f2b4726..95e16bd 100644 --- a/sources/BearURQ.Location.pas +++ b/sources/BearURQ.Location.pas @@ -5,12 +5,10 @@ interface type TLocation = class(TObject) private - FTitle: string; FContent: string; public constructor Create; destructor Destroy; override; - property Title: string read FTitle write FTitle; property Content: string read FContent write FContent; procedure Append(const S: string); procedure Clear; @@ -27,7 +25,6 @@ procedure TLocation.Append(const S: string); procedure TLocation.Clear; begin - FTitle := ''; FContent := ''; end; diff --git a/sources/BearURQ.Math.pas b/sources/BearURQ.Math.pas index 75beee5..908175d 100644 --- a/sources/BearURQ.Math.pas +++ b/sources/BearURQ.Math.pas @@ -6,6 +6,7 @@ interface Math = class class function IsDelimiter(const S: string): Boolean; class function IsNumber(const S: string): Boolean; + class function IsFunction(const S: string): Boolean; end; implementation @@ -23,6 +24,11 @@ class function Math.IsDelimiter(const S: string): Boolean; end; // Строка число или нет? +class function Math.IsFunction(const S: string): Boolean; +begin + Result := False; +end; + class function Math.IsNumber(const S: string): Boolean; var I: Integer; diff --git a/sources/BearURQ.Player.pas b/sources/BearURQ.Player.pas index 0ad6809..fe85df9 100644 --- a/sources/BearURQ.Player.pas +++ b/sources/BearURQ.Player.pas @@ -36,6 +36,7 @@ implementation uses Math, SysUtils, + Vcl.Dialogs, BearLibTerminal; var @@ -58,7 +59,6 @@ constructor TPlayer.Create; begin N := 2; FIsDebug := True; - // Box('-d'); end; if ParamCount > 0 then begin diff --git a/sources/BearURQ.Scenes.pas b/sources/BearURQ.Scenes.pas index 3c584f2..7040dc9 100644 --- a/sources/BearURQ.Scenes.pas +++ b/sources/BearURQ.Scenes.pas @@ -197,23 +197,15 @@ procedure TSceneGame.Jump(const Index: Integer); Engine.Vars.SetVarValue('previous_loc', Engine.Vars.GetVarValue('current_loc', '')); Engine.Vars.SetVarValue('current_loc', CurrLoc); - Engine.Location.Title := CurrButText; Self.Render; end; procedure TSceneGame.Render; var - I, T: Integer; + I: Integer; begin - T := 0; - // Текст последней нажатой кнопки - if (Engine.Location.Title <> '') then - begin - T := 2; - Print(0, Engine.Location.Title); - end; // Показываем содержимое окна локации - Print(0, T, Engine.Location.Content); + Print(0, 0, Engine.Location.Content); // Показываем инвентарь // Показываем все кнопки на локации diff --git a/sources/BearURQ.Utils.pas b/sources/BearURQ.Utils.pas index 741c63c..de08c3c 100644 --- a/sources/BearURQ.Utils.pas +++ b/sources/BearURQ.Utils.pas @@ -5,47 +5,51 @@ interface type TSplitResult = array of string; -function AdvLowerCase(const s: string): string; -function StrReplace(const s, Srch, Replace: string): string; +function AdvLowerCase(const S: string): string; +function StrReplace(const S, Srch, Replace: string): string; function Explode(const cSeparator, vString: string): TSplitResult; function Implode(const cSeparator: string; const cArray: TSplitResult): string; -function StrLeft(s: string; I: Integer): string; -function StrRight(s: string; I: Integer): string; -function GetINIKey(s, Key: string): string; -function GetINIValue(s, Key: string; Default: string = ''): string; +function StrLeft(S: string; I: Integer): string; +function StrRight(S: string; I: Integer): string; +function GetINIKey(S, Key: string): string; +function GetINIValue(S, Key: string; Default: string = ''): string; +function CompText(const AText, KeyWord: string): Boolean; implementation +uses + SysUtils; + // В нижний регистр -function AdvLowerCase(const s: string): string; +function AdvLowerCase(const S: string): string; var I: Integer; begin - result := s; - for I := 1 to length(result) do - if (result[I] in ['A' .. 'Z', 'А' .. 'Я']) then - result[I] := chr(ord(result[I]) + 32) - else if (result[I] in ['І']) then - result[I] := 'і'; + Result := S; + for I := 1 to Length(Result) do + if (Result[I] in ['A' .. 'Z', 'А' .. 'Я']) then + Result[I] := chr(ord(Result[I]) + 32) + else if (Result[I] in ['І']) then + Result[I] := 'і'; end; // Замена в строке -function StrReplace(const s, Srch, Replace: string): string; +function StrReplace(const S, Srch, Replace: string): string; var I: Integer; Source: string; begin - Source := s; - result := ''; + Source := S; + Result := ''; repeat I := Pos(AdvLowerCase(Srch), AdvLowerCase(Source)); if I > 0 then begin - result := result + Copy(Source, 1, I - 1) + Replace; - Source := Copy(Source, I + length(Srch), MaxInt); + Result := Result + Copy(Source, 1, I - 1) + Replace; + Source := Copy(Source, I + Length(Srch), MaxInt); end else - result := result + Source; + Result := Result + Source; until I <= 0; end; @@ -53,20 +57,20 @@ function StrReplace(const s, Srch, Replace: string): string; function Explode(const cSeparator, vString: string): TSplitResult; var I: Integer; - s: String; + S: String; begin - s := vString; - SetLength(result, 0); + S := vString; + SetLength(Result, 0); I := 0; - while Pos(cSeparator, s) > 0 do + while Pos(cSeparator, S) > 0 do begin - SetLength(result, length(result) + 1); - result[I] := Copy(s, 1, Pos(cSeparator, s) - 1); + SetLength(Result, Length(Result) + 1); + Result[I] := Copy(S, 1, Pos(cSeparator, S) - 1); Inc(I); - s := Copy(s, Pos(cSeparator, s) + length(cSeparator), length(s)); + S := Copy(S, Pos(cSeparator, S) + Length(cSeparator), Length(S)); end; - SetLength(result, length(result) + 1); - result[I] := Copy(s, 1, length(s)); + SetLength(Result, Length(Result) + 1); + Result[I] := Copy(S, 1, Length(S)); end; // Соединить массив TSplitResult в одну строку, аналог Join @@ -74,57 +78,65 @@ function Implode(const cSeparator: string; const cArray: TSplitResult): string; var I: Integer; begin - result := ''; - for I := 0 to length(cArray) - 1 do + Result := ''; + for I := 0 to Length(cArray) - 1 do begin - result := result + cSeparator + cArray[I]; + Result := Result + cSeparator + cArray[I]; end; - System.Delete(result, 1, length(cSeparator)); + System.Delete(Result, 1, Length(cSeparator)); end; // Копия строки слева -function StrLeft(s: string; I: Integer): string; +function StrLeft(S: string; I: Integer): string; begin - result := Copy(s, 1, I); + Result := Copy(S, 1, I); end; // Копия строки справа -function StrRight(s: string; I: Integer): string; +function StrRight(S: string; I: Integer): string; var L: Integer; begin - L := length(s); - result := Copy(s, L - I + 1, L); + L := Length(S); + Result := Copy(S, L - I + 1, L); end; // Ключ -function GetINIKey(s, Key: string): string; +function GetINIKey(S, Key: string): string; var P: Integer; begin - P := Pos(Key, s); + P := Pos(Key, S); if (P <= 0) then begin - result := s; + Result := S; Exit; end; - result := StrLeft(s, P - 1); + Result := StrLeft(S, P - 1); end; // Значение ключа -function GetINIValue(s, Key: string; Default: string = ''): string; +function GetINIValue(S, Key: string; Default: string = ''): string; var L, P, K: Integer; begin - P := Pos(Key, s); + P := Pos(Key, S); if (P <= 0) then begin - result := Default; + Result := Default; Exit; end; - L := length(s); - K := length(Key); - result := StrRight(s, L - P - K + 1); + L := Length(S); + K := Length(Key); + Result := StrRight(S, L - P - K + 1); +end; + +function CompText(const AText, KeyWord: string): Boolean; +var + S: string; +begin + S := Copy(AText, 1, Length(KeyWord)); + Result := CompareText(S, KeyWord) = 0; end; end.