//:://///////////////////////////////////////////// //:: Name dd_ex_port_onuse //:: FileName dd_ex_port_onuse.nss //:: Copyright © 2004-2005 by _kaa_ //::////////////////////////////////////////////// /* Пример использования dd Система порталов. При использовании показывает список всех активных порталов, при выборе переносит игрока к выбранному порталу. Добавлено: усложним пример, сделаем систему порталов а-ля диабло, т.е. требующих предварительной активации, только потом будет доступен.
*/ //::////////////////////////////////////////////// //:: Created By: _kaa_ //:: Created On: //2005 //:://////////////////////////////////////////////
//подключаем библиотеку с dd и функциями location -> string, string -> location #include "_inc_dd" #include "_inc_loc2str"
const int DD_EX_SINGLE_MODE = 0; //1 - если сингл, 0 - мультик const string DD_EX_MULTI_TAG = "dd_ex_portal"; //если мультик - ресреф и тег предмета, где будем хранить данные
const string DD_EX_COUNT = "dd_ex_count"; //имя переменной, где будем хранить количество уже запомненных порталов const string DD_EX_PORTAL = "dd_ex_portal"; //префикс сохраненных переменных с локацией запомненных порталов //полное имя переменной будет DD_EX_PORTAL+DD_EX_
//получим объект, на который будем записывать локальные переменные //для сингла вещь из инвентаря не подойдет, локальные переменные там не сохраняются, //поэтому для сингла пишем на игрока. object ex_GetObjectForSave(object oPC) { //если сингл - вернем игрока и на нем будем писать переменные if (DD_EX_SINGLE_MODE) return oPC; //если мультик - найдем вещь в инвентаре у игрока с тегом MULTI_TAG object oItem = GetItemPossessedBy(oPC,DD_EX_MULTI_TAG); if (GetIsObjectValid(oItem)) return oItem; //нету еще такой вещи - создадим oItem = CreateItemOnObject(DD_EX_MULTI_TAG,oPC); if (GetIsObjectValid(oItem)) return oItem; //кривой ресреф, нельзя создать вещь - ошибка. return OBJECT_INVALID;
}
//проверим, активен ли уже данный портал для игрока. если нет - сохраним void ex_IsAlreadyChecked(object oPC, object oPortal) { object oStore = ex_GetObjectForSave(oPC); //проверим, есть ли у нас объект для записи переменных if (!GetIsObjectValid(oStore)) { //ошибка, сообщим и выходим WriteTimestampedLogEntry("Error! Can't get object for store."); return; } //убедимся, что oPortal - действительно объект. if (!GetIsObjectValid(oPortal)) { //ошибка, сообщим и выходим WriteTimestampedLogEntry("Error! oPortal is not valid object."); return; }
//получим локацию портала в виде строки. string sLoc = LocationToString(GetLocation(oPortal));
//с объекта oStore узнаем, сколько уже на нем есть записей. int n = GetLocalInt(oStore,DD_EX_COUNT);
int i; if (n) for (i=0; i <=n; i++) { if (sLoc == GetLocalString(oStore,DD_EX_PORTAL+IntToString(i))) //нашли, выходим return; } //не нашли, надо запомнить и увеличить счетчик n++; SetLocalString(oStore,DD_EX_PORTAL+IntToString(n),sLoc); SetLocalInt(oStore,DD_EX_COUNT,n); //надо бы сюда добавить какой-нибудь визуальный эффект при добавлении. //для сингла пойдет анимация портала, для мультика - любой виз. эффект на игрока
//а пока просто напишем игроку, что портал активирован FloatingTextStringOnCreature("Портал "+GetName(GetArea(oPortal))+"."+GetName(oPortal)+" активирован",oPC,TRUE); }
void main() { //Кто кликнул на портал object oLastUsed = GetLastUsedBy(); //точно игрок кликнул на портал? if (!GetIsPC(oLastUsed)) return; //если игрок еще в битве - сразу выходим, диалог все равно не запустится. //можно добавить вывод предупреждения. if (GetIsInCombat(oLastUsed)) return;
//инициализируем dd. для игрока oLastUsed() //приветствие диалога - "Порталы" //скрипт обработки - "dd_ex_port_jump" //размер "окна" - 10 (максимальное количество пунктов в диалоге, от 3 до 10 //используем вариант без второго уровня диалогов, т.е. без подтверждения if (!dd_Init(oLastUsed,"Порталы","dd_ex_port_jump",10,FALSE)) { //произошла ошибка инициализации, выходим return; }
/* //1. "простой" вариант, просто перебирает все плейсиблы-порталы.
//найдем все порталы (все плейсиблы с тегом"dd_ex_portal") int n = 0; object oPortal = GetObjectByTag("dd_ex_portal",0); while (GetIsObjectValid(oPortal)) { n++; if (oPortal != OBJECT_SELF && GetObjectType(oPortal) == OBJECT_TYPE_PLACEABLE) //и добавим пару (описание, значение) в диалог. //описание - название локации + имя плейсибла //значение - текстовое представление типа location, которое //не меняется при добавление\удаленние но зависит //от уникальности тегов локаций, если будут одинаковые теги //локации - телепорты будут глючить. dd_Add(oLastUsed,GetName(GetArea(oPortal))+"."+GetName(oPortal),LocationToString(GetLocation(oPortal))); oPortal = GetObjectByTag("dd_ex_portal",n); } */ /*2. Чуть более сложный вариант, а-ля диабло. Портал требует активации, только потом доступен удаление уже активного портала из списка не планируется делать, если "приспичило" - просто удалите предмет, на который "сохраняются" переменные (для мультика) */
//проверим, запомнен ли уже этот портал? если нет - запомним. ex_IsAlreadyChecked(oLastUsed,OBJECT_SELF);
//получим объект, на котором хранятся переменные object oStore = ex_GetObjectForSave(oLastUsed); //проверим, действительно ли у нас есть объект для записи переменных if (!GetIsObjectValid(oStore)) { //ошибка, сообщим и выходим WriteTimestampedLogEntry("Error! Can't get object for store."); return; }
//с объекта oStore узнаем, сколько уже на нем есть записей. //каждую запись добавим в диалог int n = GetLocalInt(oStore,DD_EX_COUNT); object oPortal; string sLoc; int i; for (i=1; i <=n; i++) { //читаем по очереди все сохраненные локации порталов. sLoc = GetLocalString(oStore,DD_EX_PORTAL+IntToString(i)); //найдем объект (ближайший плейсибл к сохранненой локации) oPortal = GetNearestObjectToLocation(OBJECT_TYPE_PLACEABLE,StringToLocation(sLoc)); //и проверим, действительно ли это портал? if (!GetIsObjectValid(oPortal)) { //ошибка, сообщим и выходим WriteTimestampedLogEntry("Error! Wrong saved location :"+sLoc); return; }
/*в этом месте можно добавить дополнительную проверку типа и тега объекта oPortal, например если вы хотите сделать более чем одну "сеть" порталов. в примере все порталы имеют один тег, "dd_ex_portal". если мы добавим проверку и будем требовать, чтобы тег портала, на котором кликнули и тег "удаленного" портала совпадали, мы можем разбить порталы на непересекающиеся "сети" порталов: //для этого нам нужно будет создать "синьку" (т.е. новый тип объектов в палитре модуля) нового типа порталов и сменить ему тег. */ if (GetTag(OBJECT_SELF) != GetTag(oPortal)) continue;
/*проверим, если на портале есть переменная only_exit - значит можно на него прыгать, но не с него.чтобы не путать игроков - смените внешний вид плейсибла или каким-то другим способом дайте понять что он не работает */ if (GetLocalInt(OBJECT_SELF,"only_exit")) { FloatingTextStringOnCreature("Портал работает только в одну сторону",oLastUsed); return; } /* проверим, если на портале есть переменная only_enter - значит можно c него прыгать, но не на него (т.е. в списке доступных порталов его не будет, хотя с него можно прыгнуть на другие) чтобы не путать игроков - смените внешний вид плейсибла или каким-то другим способом дайте понять что он не работает */ if (GetLocalInt(oPortal,"only_enter")) continue;
//если не нужно выводить в диалог тот портал, по которому кликнули - добавим if (OBJECT_SELF != oPortal) //если все верно - запишем название локации и самого портала в диалог dd_Add(oLastUsed,GetName(GetArea(oPortal))+"."+GetName(oPortal),sLoc); }
/* посколько диалог идет "сам с собой", нужно пердусмотреть его закрытие. иначе "умные" игроки пойдут воевать с открытым диалогом, чтобы можно было "сбежать" из боя. поэтому запомним в переменной на игроке объект- портал и при запуске "action" проверим расстояние до него / */ SetLocalObject(oLastUsed,"dd_ex_port_obj",OBJECT_SELF);
//запустить диалог. dd_Show(oLastUsed); } |