Новости/News | | Туториалы/Tutorials | | Форум/Forum | | ЧаВо/FAQ | | Файлы/Downloads | | Ссылки/Links | | Авторы/About |

Продвинутые сообщения

В этом небольшой туториале показано, как переопределить функции Say() (и TeamSay()) из класса PlayerPawn для того, чтобы игроки могли пользоваться определенными escape кодами во время передачи сообщения. Чтобы все выглядело аккуратно, я просто создал новую функцию ParseChatString(), которая принимает в качестве параметра текст сообщения, разбирает его на составляющие, модифицирует его исходя из содержания и, затем, возвращает конечную строку сообщения. Также я написал новые версии функций Say() и TeamSay(), которые в свою очередь вызывают метод ParseChatString() и отображают на экране модифицированное сообщение. Поэтому, теоретически, если Вы хотите интегрировать этот подход в Ваш мод, Вы можете просто вставить эти три функции в созданный Вами подкласс класса PlayerPawn.

ParseChatString принимает строку сообщения, затем перебирает ее посимвольно, ища при этом символ #. Как только такой символ найден, скрипт обращается к следующему символу, и, исходя из того, каким является следующий символ, вставляет соответствующую информацию в конечную строку, затем продолжает поиск других символов #, и так до конца исходной строки. Затем функция возвращает измененную строку сообщения.

// function string ParseChatString(string Msg)
//
// escape коды:
// =============
// #N - имя игрока
// #L - положение игрока
// #S - статус игрока (здоровье/броня)
// #H - здоровье игрока
// #A - броня игрока
// #B - друзья, перечисляет всех "дружественных" игроков в определенном радиусе
// #W - оружие игрока
// #T - тестовый код
// ## - выводит символ '#'
//
// Для поиска друзей скрипт использует свойство RadiusActors (радиус актера),
// затем проверяет, является ли актер "дружественным", т.е. проверяет
// в одной ли Вы команде, и если так, то добавляет его в список друзей (bStr),
// затем, когда весь список готов, преобразовывает строку в "грамматически"
// правильную, т.е. добавляет союзы "and" между именами. Я знаю, что это
// трата времени, но я был в шоке от того, что это заработало с первого раза :)
//
// Если Вы хотите иметь больше escape кодов, просто добавьте дополнительные
// case в операторе switch, где и дописывайте к конечной строке
// нужную Вам информацию 
//
// Что еще:
// - можно сделать многоуровневые escape коды, например, #b:5 возвращающий
//   только пять друзей

function string ParseChatString(string Msg)
{
  local int i, amt, numBuddy, lBuddyLen;
  local float BuddyRadius;
  local string nMsg, tStr, bStr, lbStr;
  local Inventory Inv;
  local Pawn Buddy;
  local PlayerReplicationInfo mPRI, bPRI;

  BuddyRadius = 1500.0;
  mPRI = PlayerReplicationInfo;

  // перебираем посимвольно всю строку в поисках символа #
  // Len(string) возвращает длину строки
  for (i = 0;i <= Len(Msg);i++)
  {
    // используем функцию Mid для получения определенного символа в строке,
    // т.к. выражение Msg[i] не работает
    // Mid(string, pos, count) возвращает подстроку данной строки, начиная
    // с позиции pos и кончая pos+count-1 (включительно), поэтому, чтобы
    // вытащить один символ из строки, указываем count равный 1
    if (Mid(Msg, i, 1) == "#")
    {
      // найден escape символ #,
      // теперь необходимо узнать следующий за ним символ
      i += 1;
      tStr = Mid(Msg,i,1);

      // здесь находится сердце функции - switch оператор,
      // если нужно больше escape кодов, просто добавьте
      // необходимое количество case-ов
      switch (tStr)
      {
        // оружие игрока - вставляет наименование Вашего оружия
        case "W":
          nMsg = nMsg $ Weapon.ItemName;
          break;

        // имя игрока - вставляет Ваше имя
        case "N":
          nMsg = nMsg $ mPRI.PlayerName;
          break;

        // положение игрока - вставляет Ваше местоположение
        case "L":
          if (mPRI.PlayerLocation != NONE)
            nMsg = nMsg $ mPRI.PlayerLocation.LocationName;
          else if (mPRI.PlayerZone != NONE)
            nMsg = nMsg $ mPRI.PlayerZone.ZoneName;
          else nMsg = nMsg $ "somewhere";
          break;

        // броня игрока - вставляет количество Вашей брони
        case "A":
          amt = 0;
          for (Inv = Inventory; Inv != NONE; Inv = Inv.Inventory)
            if (Inv.bIsAnArmor)
              amt += Inv.Charge;
          nMsg = nMsg $ amt;
          break;

        // здоровье игрока - вставляет количество Вашего здоровья
        case "H":
          nMsg = nMsg $ Health;
          break;

        // статус игрока - вставляет Ваш статус (Health: xxx Armor: xxx)
        case "S":
          amt = 0;
          for (Inv = Inventory; Inv != NONE; Inv = Inv.Inventory)
            if (Inv.bIsAnArmor)
              amt += Inv.Charge;
          nMsg = nMsg $ "Health: " $ Health $ " Armor: " $ amt;
          break;

        // друзья - вставляет список друзей,
        // находящихся в определенном радиусе
        case "B":
          numBuddy = 0;
          foreach RadiusActors(class'Pawn', Buddy, BuddyRadius)
          {
            bPRI = Buddy.PlayerReplicationInfo;
            if (Buddy != Self && Buddy.bIsPlayer && bPRI.Team == mPRI.Team)
            {
              lbStr = bPRI.PlayerName;
              lBuddyLen = Len(lbStr);
              if (numBuddy < 1)
                bStr = lbStr;
              else bStr = bStr $ ", " $ lbStr;
              numBuddy++;
            }
          }

          // вставляем в список друзей союзы "and" между их именами
          // в случае если их больше одного. Эх, грамматика, грамматика...
          if (numBuddy >= 3)
            bStr = Left(bStr, Len(bStr) - lBuddyLen) $ " and " $ lbStr;
          else if (numBuddy == 2)
            bStr = Left(bStr, Len(bStr) - lBuddyLen - 2) $ " and " $ lbStr;
          else if (numBuddy == 0)
            bStr = "nobody";

          nMsg = nMsg $ bStr;
          break;

        // тестовый символ - ничего не вставляет
        case "T":
          nMsg = nMsg $ "<test>";
          break;

        // символ '#' - вставляет символ '#' (мало ли - может понадобится :)
        case "#":
          nMsg = nMsg $ "#";
          break;
        default:
          break;
      }
    }

    // если символ не является escape кодом (#),
    // просто дописываем его в конечную строку
    else nMsg = nMsg $ Mid(Msg, i, 1);
  }

  // и, наконец, возвращаем модифицированное сообщение
  return nMsg;
}

На этом этапе осталось только "заставить" Ваши функции Say() и TeamSay() вызывать метод ParseChatString(), а затем, для вывода сообщения воспользоваться услугами родительских Say() и TeamSay() функций.

exec function Say( string Msg ) {

  // подвергаем сообщение модификации
  Msg = ParseChatString(Msg);

  // вызываем родительский метод Say()
  // для вывода нового сообщения на экран
  Super.Say(Msg);
}

exec function TeamSay(string Msg) {

  // подвергаем сообщение модификации
  Msg = ParseChatString(Msg);

  // вызываем родительский метод SayTeam()
  // для вывода нового сообщения на экран
  Super.TeamSay(Msg);
}

Вот и все. Если Вы хотите использовать это, Вы должны вставить этот скрипт в новый подкласс класса PlayerPawn и затем поменять Ваш ut.ini или создать новый тип игры (GameType), для того, чтобы быть уверенным, что порождается (spawn) именно новый класс... но это уже не укладывается в рамки этого туториала.

Автор

crack_addict
Источник: www.unrealscript.com
Перевод сделан 32_Pistoleta

Хостинг от uCoz