![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
![]()
Сообщение
#111
|
|
Level 11 ![]() Класс: Волшебник Характер: Neutral Good Раса: Фея NWN: Скриптинг [PW] Край Лесов ![]() |
Как-то давно мне пришла в голову интересная мысль и захотелось ее реализовать - деньги в нвн не просто золотые, а монеты с весом. На ваулте лежало несколько реализаций, но меня они не устраивали, в виду некоторых причин их реализации.
Для работы системы нужен NWNX и 2 плагина nwnx_events и nwnx_fixes Суть: 2 типа магазина: скупщик и продающий Зацепляем событие на Еxamine item в nwnx_events Берем голд-стоимость итема, вычисляем. В мое случае это 1 электрум = 100 золото = 10000 серебро 3 вида вычислений стоимости: 1). Когда еxamine item производиться просто в инвентаре, без открытого магазина. -выдается стоимость без всяких надбавок + экономическое изменение (можно регулировать общее подорожание или удешевление) 2). С открытым магазине типа продающий -производиться оценка, обоюдный бросок – в зависимости от этого скидки или наценка + экономическое изменение 3). в инвентаре при открытом магазине типа скупщик -производиться оценка, обоюдный бросок – в зависимости от этого скидки или наценка + экономическое изменение Надо добавить, что при реализации идеи использовались наработки КЛ, в частности - по поломке предметов, так что его (предмета) состояние непосредственно влияло на стоимость продажи/покупки Результат выводиться виде сообщения игроку, когда он смотрит свойства предмета. Продажа/Покупка осуществляется через REMOVE_DISTURBED_ITEM, простым перетаскиванием, без всяких диалогов. На магазин вешается переменная с ДЦ ОЦЕНКИ и типом магазина. Всего два действия по сути: первое вы смотрите стоимость во время просмотра свойств, второе – покупка/продажа =) Значит, обычный плэйс, с инвентарем. На нем 2 локалки типа int TD_MERCANT_DC - ДЦ для ОЦЕНКИ и TD_MERCANT - тип магазина 1 и 2 Название валют можно придумать свои, для простоты ориентации в скрипте: MonE - это сама дорогая (Электрумовая) = 100 золотым = 10000 серебра MonG - средняя (Золотая) = 100 серебрянным MonS - нифиля (Сребрянная) Т.е. грубо говоря если в разных городах разные валюты (города в разных странах), то стоимость итема будет выдана в той валюте, которая в городе с учетом той экономической ситуации, которая в стране. Была идея сделать разные наценки в городах, в зависимости от типов предмета. Например, на мечи - такая, на бронь - такая. Что-то типо предложения спроса в городе. Идея не воплотилась) Скрипты: nwnx_events Neverwinter Script const int TD_SECS_IN_HOUR = 120.0f; // Melisse: Берет goldvalue предмета и переводит его в валюту и выдает ввиде сообщения игроку void td_SendMessageItemMoneyCost (object oPC, object oInvent, object oTarget); // Main void main( ){ object oPC = OBJECT_SELF; object oTarget = GetNWNXEventTarget( ); int nEvent = GetNWNXEventType( ); switch( nEvent ){ case EVENT_EXAMINE: { if(GetObjectType(oTarget) == OBJECT_TYPE_ITEM) { object oInvent = GetItemPossessor(oTarget); if(GetPlotFlag(oTarget) == FALSE) td_SendMessageItemMoneyCost (oPC, oInvent, oTarget); } else SendMessageToPC( oPC, "NWNX Knows you just examined "+GetName( oTarget )+"!" ); break; } } } void td_SendMessageItemMoneyCost (object oPC, object oInvent, object oTarget) { int nInvent = (GetObjectType(oInvent) == OBJECT_TYPE_PLACEABLE); int nCost = GetGoldPieceValue(oTarget); SendMessageToPC (oPC, "============================================= ===="); //SendMessageToPC (oPC, "Value = "+IntToString(nCost)); SendMessageToPC (oPC, td_ColorText(GetName(oTarget),TD_TXT_COLOR_GRAY)); /* Закоментровано. Это относитсья к системе поломки, которую тут не выкладываю. // Вычислим стоимость, если итем сломан struct strItemDur strMyItemDur = td_GetItemDur(oTarget); int nDurCur = strMyItemDur.nDurCur; int nDurMax = strMyItemDur.nDurMax; int nDurResult = nDurMax - nDurCur; if(nDurResult > 0) { float fBroken = IntToFloat(nCost)/100.0*IntToFloat(nDurResult); nCost -= FloatToInt(fBroken); SendMessageToPC (oPC, "Сломан! = -"+IntToString(nDurResult)+ "% от полной цены"); }*/ // Если просмотр производиться в чьем-то инвентаре if(GetIsObjectValid(oInvent)) { // Магазин // При просмотре описания с открытым магазином // стоимость товара учитывает со скидкой/наценкой if(GetLocalInt(oInvent, "TD_MERCANT")) { int nSell = FALSE; object oStore; if (oPC == oInvent) { // Игрок продает oStore = GetLocalObject(oPC, "TD_MERCANT_OBJ"); nSell = TRUE; } else if(nInvent) { // Игрок покупает oStore = oInvent; } else return; string sCharID = IntToString(GetLocalInt (oPC, "nCharID")); int nDiscount = GetLocalInt (oStore, "TD_DISCOUNT"+sCharID); int nTime = GetLocalInt (oStore, "TD_DISCOUNT_TIME"+sCharID); int nEcoKingdom = GetLocalInt (GetModule(), "TD_MOD_ECO" +GetSubString(GetTag(GetArea(oPC)), 2, 1)); SendMessageToPC (oPC, "Экономическая ситуация = "+IntToString(nEcoKingdom)+"%"); // Рачитаем на сколько поднимиться цена в этой стране на этот предмет nEcoKingdom = FloatToInt(IntToFloat(nCost)/100.0*IntToFloat(nEcoKingdom)); // Скидки нет или время пришло (1 раз в сутки) if(!nDiscount || nTime < td_Uptime()) { int nDC = GetLocalInt(oStore, "TD_MERCANT_DC"); int nSkill = GetSkillRank(SKILL_APPRAISE, oPC); nDiscount = nDC - nSkill; if(nDiscount < 0) nDiscount *= -1; if(nDiscount == 0) nDiscount = 1; if(GetIsSkillSuccessful(oPC, SKILL_APPRAISE, nDC)) { if(!nSell) { nDiscount += 100; } SetLocalInt (oStore, "TD_DISCOUNT"+sCharID, nDiscount); } else { if(nSell) { nDiscount += 100; } SetLocalInt (oStore, "TD_DISCOUNT"+sCharID, nDiscount); } SetLocalInt (oStore, "TD_DISCOUNT_TIME"+sCharID, td_Uptime ()+24*TD_SECS_IN_HOUR ); } // Скидка есть - расчитаем if(nDiscount >= 100) { nDiscount -= 100; float fDiscount = IntToFloat(nCost)/100.0*IntToFloat(nDiscount); if(nSell) { SendMessageToPC (oPC, "Продажа: цена = +"+IntToString(nDiscount)+"%"); nCost += FloatToInt(fDiscount)-nEcoKingdom; // С учетом общего экономического состояния в стране } else { nCost -= FloatToInt(fDiscount)+nEcoKingdom; // С учетом общего экономического состояния в стране SendMessageToPC (oPC, "Покупка: скидка = -"+IntToString(nDiscount)+"%"); } } else { float fDiscount = IntToFloat(nCost)/100.0*IntToFloat(nDiscount); if(nSell) { SendMessageToPC (oPC, "Продажа: цена = -"+IntToString(nDiscount)+"%"); nCost -= FloatToInt(fDiscount)-nEcoKingdom; // С учетом общего экономического состояния в стране } else { nCost += FloatToInt(fDiscount)+nEcoKingdom; // С учетом общего экономического состояния в стране SendMessageToPC (oPC, "Покупка: цена = +"+IntToString(nDiscount)+ "%"); } } //SendMessageToPC (oPC, "Игрок = "+GetName(oPC)); //SendMessageToPC (oPC, "Магазин = "+GetName(oStore)); } } // Переведем в денежынй эквивалент int nMonE = nCost/10000; // Электрумовые int nMonG = (nCost - nMonE*10000)/100; // Золотые int nMonS = nCost - (nMonG*100+nMonE*10000); // Серебряные // Покажем игроку результаты SendMessageToPC (oPC, td_ColorText("*СТОИМОСТЬ:",TD_TXT_COLOR_GRAY)); SendMessageToPC (oPC, td_MoneyName(GetArea(oPC),nMonS,nMonG,nMonE)); } на OnOpen на плэйсе Neverwinter Script void main() { object oPC = GetLastOpenedBy(); // Магазин, который скупает if(GetIsPC(oPC) && GetLocalInt(OBJECT_SELF, "WS_MERCANT") == 2) { SetLocalInt(oPC, "WS_MERCANT", TRUE); SetLocalObject(oPC, "WS_MERCANT_OBJ", OBJECT_SELF); } // Запускается проверка на "Опознание" предметов в инвентаре магазина // 1 раз за рестарт, при 1-вом открытии if(!GetLocalInt(OBJECT_SELF, "nActiveted")) { object oItem = GetFirstItemInInventory(OBJECT_SELF); while (GetIsObjectValid(oItem)) { if(!GetIdentified(oItem)) SetIdentified(oItem, TRUE); int nBaseType = GetBaseItemType(oItem); // Выставляем на итемы со стэком > 1 // Это необходимо для того, чтобы они не стыкались с теми что в инвентаре // nwnx_fixed убирает баг, при котором стэкались итемы, когда у них локалки if(nBaseType == BASE_ITEM_ARROW || nBaseType == BASE_ITEM_BOLT || nBaseType == BASE_ITEM_BULLET || nBaseType == BASE_ITEM_DART || nBaseType == BASE_ITEM_POTIONS || nBaseType == BASE_ITEM_THROWINGAXE) { SetLocalInt(oItem, "WS_MERCANT_ITEM", TRUE); } oItem = GetNextItemInInventory(OBJECT_SELF); } SetLocalInt(OBJECT_SELF, "nActiveted", TRUE); } } на OnDisturbed на плэйсе Neverwinter Script /**************************************\ td_pds_shop -------------------------- Author : Melisse E-mail : ICQ : Started : -------------------------- Скрипт магазина \**************************************/ //#include "td_inc_craft" void td_ReturnItem (object oSubject, object oItem); void main() { object oMerchant = OBJECT_SELF; object oPC = GetLastDisturbed(); object oItem = GetInventoryDisturbItem(); object oArea = GetArea(oPC); string sMonE = td_GetTagMoney(GetTag(oArea), "sMonE"); string sMonG = td_GetTagMoney(GetTag(oArea), "sMonG"); string sMonS = td_GetTagMoney(GetTag(oArea), "sMonS"); string sTradeType = GetLocalString(oMerchant, "sTradeType"); int nDistType = GetInventoryDisturbType(); int nMoneyPC = td_GetCountAllMoney (oPC, sMonE, sMonG, sMonS); int nCost = GetGoldPieceValue(oItem); /* Закоментровано. Это относитсья к системе поломки, которую тут не выкладываю. // Вычислим стоимость, если итем сломан struct strItemDur strMyItemDur = td_GetItemDur(oItem); int nDurCur = strMyItemDur.nDurCur; int nDurMax = strMyItemDur.nDurMax; if((nDurMax - nDurCur) > 0) { float fCost = IntToFloat(nCost)/100.0*IntToFloat(nDurCur); nCost -= FloatToInt(fCost); } */ // стоимость товара учитывает со скидкой/наценкой string sCharID = IntToString(GetLocalInt (oPC, "nCharID")); int nDiscount = GetLocalInt (oMerchant, "TD_DISCOUNT"+sCharID); int nTime = GetLocalInt (oMerchant, "TD_DISCOUNT_TIME"+sCharID); int nSell = FALSE; int nEcoKingdom = GetLocalInt (GetModule(), "TD_MOD_ECO_" +GetSubString(GetTag(GetArea(oPC)), 2, 1)); if(GetLocalInt(oMerchant, "TD_MERCANT") == 2) nSell = TRUE; // Рачитаем на сколько поднимиться цена в этой стране на этот предмет nEcoKingdom = FloatToInt(IntToFloat(nCost)/100.0*IntToFloat(nEcoKingdom)); // ---- // Вычисление скидки/наценки // ---- if(!nDiscount || nTime < td_Uptime()) { int nDC = GetLocalInt(oMerchant, "TD_MERCANT_DC"); int nSkill = GetSkillRank(SKILL_APPRAISE, oPC); nDiscount = nDC - nSkill; if(nDiscount < 0) nDiscount *= -1; if(nDiscount == 0) nDiscount = 1; if(GetIsSkillSuccessful(oPC, SKILL_APPRAISE, nDC)) { if(!nSell) { nDiscount += 100; } SetLocalInt (oMerchant, "TD_DISCOUNT"+sCharID, nDiscount); } else { if(nSell) { nDiscount += 100; } SetLocalInt (oMerchant, "TD_DISCOUNT"+sCharID, nDiscount); } SetLocalInt (oMerchant, "TD_DISCOUNT_TIME"+sCharID,td_Uptime()+24*TD_SECS_IN_HOUR ); } // Скидка есть - расчитаем if(nDiscount >= 100) { nDiscount -= 100; float fDiscount = IntToFloat(nCost)/100.0*IntToFloat(nDiscount); if(nSell) { //SendMessageToPC (oPC, "Повышение цены = "+IntToString(nDiscount)+ "%"); nCost += FloatToInt(fDiscount)-nEcoKingdom; // С учетом общего экономического состояния в стране } else { nCost -= FloatToInt(fDiscount)+nEcoKingdom; // С учетом общего экономического состояния в стране //SendMessageToPC (oPC, "Скидка = "+IntToString(nDiscount)+ "%"); } } else { float fDiscount = IntToFloat(nCost)/100.0*IntToFloat(nDiscount); if(nSell) { //SendMessageToPC (oPC, "Снижение цены = "+IntToString(nDiscount)+ "%"); nCost -= FloatToInt(fDiscount)-nEcoKingdom; // С учетом общего экономического состояния в стране } else { nCost += FloatToInt(fDiscount)+nEcoKingdom; // С учетом общего экономического состояния в стране //SendMessageToPC (oPC, "Наценка = "+IntToString(nDiscount)+ "%"); } } // ---- // Процесс Покупка/Продажа // ---- if(nDistType == INVENTORY_DISTURB_TYPE_REMOVED) { if(GetPlotFlag(oItem) || GetLocalInt(oMerchant, "TD_MERCANT") != 1) { td_ReturnItem (oMerchant, oItem); FloatingTextStringOnCreature ("Этот предмет не продается.", oPC, FALSE); } else if(nMoneyPC < nCost) { td_ReturnItem (oMerchant, oItem); FloatingTextStringOnCreature ("Не хватает денег для покупки этой вещи.", oPC, FALSE); } else { // ------- // Транзакция денег и выдача предмета // ------- td_MoneyTransaction (oPC, TRUE, nMoneyPC, nCost, sMonE, sMonG, sMonS); CopyItem (oItem, oMerchant, TRUE); DeleteLocalInt(oItem, "TD_MERCANT_ITEM"); } AssignCommand(oPC, ActionInteractObject(oMerchant)); DelayCommand(0.5f, AssignCommand(oPC, ActionInteractObject(oMerchant))); } else if (nDistType == INVENTORY_DISTURB_TYPE_ADDED) { if(GetPlotFlag(oItem) || GetLocalInt(oMerchant, "TD_MERCANT") != 2) { td_ReturnItem (oPC, oItem); FloatingTextStringOnCreature ("*Вы не можете продать этот предмет здесь.", oPC, FALSE); } // Нельзя продать не идентифицированый итем или продать предмет который не покупает магазин else if (!GetIdentified (oItem) || FindSubString(sTradeType, IntToString(GetBaseItemType (oItem))) == -1) { td_ReturnItem (oPC, oItem); FloatingTextStringOnCreature ("*Вы не можете продать этот предмет здесь.", oPC, FALSE); } else { // ------- // Транзакция денег и удаление проданого предмета // ------- td_MoneyTransaction (oPC, FALSE, nMoneyPC, nCost, sMonE, sMonG, sMonS); SetLocalInt(oItem, "TD_DESTROY",TRUE); DestroyObject(oItem,0.5f); } AssignCommand(oPC, ActionInteractObject(oMerchant)); DelayCommand(0.5f, AssignCommand(oPC, ActionInteractObject(oMerchant))); } } void td_ReturnItem (object oSubject, object oItem) { CopyItem (oItem, oSubject, TRUE); DestroyObject (oItem); } Далее выкладываю просто функции и их прототипы: Neverwinter Script // Возвращает текстовую строку со стоимость и названиями валют // Можно устанавливать разные валюты для разных городов и тут высталять названия string ws_MoneyName(int nMoneyS, int nMoneyG = 0, int nMoneyE = 0); string ws_MoneyName(int nMoneyS, int nMoneyG = 0, int nMoneyE = 0) { sText = ws_ColorText(IntToString(nMoneyE)+" Хан ",WS_TXT_COLOR_WHITE) + ws_ColorText(IntToString(nMoneyG)+" Мон ",WS_TXT_COLOR_YELLOW) + ws_ColorText(IntToString(nMoneyS)+ " Шо",WS_TXT_COLOR_CYAN); return sText; } // Возвращает полное количество денег в GoldValue int ws_GetCountAllMoney (object oSubject, string sMonE, string sMonG, string sMonS); int ws_GetCountAllMoney (object oSubject, string sMonE, string sMonG, string sMonS) { object oMoney = GetFirstItemInInventory(oSubject); int i; while (GetIsObjectValid(oMoney)) { string sMoney = GetTag(oMoney); if(sMoney == sMonE) i += GetNumStackedItems(oMoney)*10000; else if (sMoney == sMonG) i += GetNumStackedItems(oMoney)*100; else if (sMoney == sMonS) i += GetNumStackedItems(oMoney); oMoney = GetNextItemInInventory(oSubject); } return i; } // Производит пересоздание денег у игрока void ws_MoneyTransaction (object oPC, int nType, int nMoneyPC, int nCost, string sMonE, string sMonG, string sMonS); void ws_MoneyTransaction (object oPC, int nType, int nMoneyPC, int nCost, string sMonE, string sMonG, string sMonS) { int nResult; if(nType) // Покупка предмета nResult = nMoneyPC - nCost; else // Продажа предмета nResult = nMoneyPC + nCost; SendMessageToPC (oPC, "Было денег = "+IntToString(nMoneyPC)+" Стоимость итема = "+IntToString(nCost)+" Стало денег = "+IntToString(nResult) ); int nMonE = nResult/10000; // Электрумовые int nMonG = (nResult - nMonE*10000)/100; // Золотые int nMonS = nResult - (nMonG*100+nMonE*10000); // Серебряные /* SendMessageToPC (oPC, "Эле = "+IntToString(nMonE)+" Золо = "+IntToString(nMonG)+" Сере = "+IntToString(nMonS) );*/ object oItem = GetFirstItemInInventory(oPC); while (GetIsObjectValid(oItem)) { string sTag = GetTag(oItem); if (sTag == sMonE || sTag == sMonG || sTag == sMonS) { SetLocalInt(oItem, "WS_DESTROY",TRUE); DestroyObject(oItem); } oItem = GetNextItemInInventory(oPC); } object oNew; if(nMonS) { oNew = CreateItemOnObject(sMonS, oPC); SetItemStackSize (oNew, nMonS); } if(nMonG) { oNew = CreateItemOnObject(sMonG, oPC); SetItemStackSize (oNew, nMonG); } if(nMonE) { oNew = CreateItemOnObject(sMonE, oPC); SetItemStackSize (oNew, nMonE); } } // Возвращает тэг валюты sMoneyType используемой в этом городе string ws_GetTagMoney (string sAreaTag, string sMoneyType); string ws_GetTagMoney (string sAreaTag, string sMoneyType) { string sTown = sAreaTag; string sMoneyTag; if(sTown == "Area001") { if(sMoneyType == "sMonE") sMoneyTag = "IT_MON_FE"; else if (sMoneyType == "sMonG") sMoneyTag = "IT_MON_FG"; else if (sMoneyType == "sMonS") sMoneyTag = "IT_MON_FS"; } return sMoneyTag; } Скрипты и функции выдернуты из целого комплекса систем, поэтому могут быть какие-то не компиляции, но суть мысли должна быть понятна. Сообщение отредактировал Melisse - Oct 21 2011, 17:29 |
![]()
Сообщение
#112
|
|
Тролль ![]() ![]() ![]() ![]() Класс: Пьяный Мастер Характер: Chaotic Neutral Раса: Тварь ![]() |
Люди только осваивающие скрипты в тулсете довольно часто спрашивают как сделать, чтоб объект появлялся в локации только в определенное время (эдакие лунные руны по Толкиену (IMG:style_emoticons/kolobok_light/smile.gif) ). Продвинутые модульмэйкеры знают сотню способов как это реализовать, однако недавно копался в очередной раз над наиболее лаконичным ответом на этот вопрос в тулсете (пользуясь случаем передаю привет Аконит (IMG:style_emoticons/kolobok_light/biggrin.gif) ) – и обнаружил довольно универсальную формулу скрипта:..
Neverwinter Script void main() ...Комментарии на английском из-за возможных боков с "я" вот их перевод для не знающих:{ object oTarget = OBJECT_SELF; effect eEffect = EffectDisappearAppear(GetLocation(OBJECT_SELF), 1); int DoOnce = GetLocalInt(OBJECT_SELF, GetTag(OBJECT_SELF)); float fHour = 60.0; //<- hour longitude in module (in seconds) int iHour = 0; //<- hour of appear (from 0 to 23) int iTimeout = 1; //<- longitude of appear (in hours, from 1 to 23) int iDifferent; iDifferent = iHour+iTimeout; if (iDifferent > 23) { iDifferent = iDifferent-24; } if ((GetTimeHour()==iDifferent)&&(DoOnce==FALSE)) { ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oTarget, fHour*(24-iTimeout)); SetLocalInt(OBJECT_SELF, GetTag(OBJECT_SELF), TRUE); DelayCommand(fHour*(24-iTimeout), SetLocalInt(OBJECT_SELF, GetTag(OBJECT_SELF), FALSE)); } } <- hour longitude in module (in seconds)/длительность игрового часа в модуле (в секундах) <- hour of appear (from 0 to 23)/игровой час появления объекта (от 0 до 23) <- longitude of appear (in hours, from 1 to 23)/длительность появления объекта (в игровых часах, от 1 до 23) Эти значения вы должны подставить в скрипт сами в соответствии с особенностями модуля и собственно эвента с объектом. Скрипт нужно ставить на OnHeartbeat существа/объекта, при этом если это объект - он не должен иметь в своих свойствах галочку в окошке "статик", иначе скрипт не сработает (однако при этом объект не обязательно должен быть "активным"). У скрипта есть единственный недостаток - при старте модуля объект будет видимым, пока и если в модуле не наступит час его исчезновения. Далее скрипт будет работать исправно. |
![]() ![]() |
Текстовая версия | Сейчас: 7th July 2025 - 16:03 |