• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!
  • Друзья, доброго времени суток!
    Стартовал новый литературный конкурс от "Ордена Хранителей" - "Пираты Миртанского моря".
    Каждый может принять в нём участие и снискать славу и уважение, а в случае занятия призового места ещё и получить награду. Дерзайте
  • Дорогие друзья, год подходит к концу, и пришло время подвести его итоги и наградить достойных

    Не ленитесь, голосуйте в этой теме за тех форумчан, которые по вашему мнению больше всех проявили себя в этом году
    По желанию, аргументировать свой выбор можете в теме обсуждения голосования.

Создание заклинания "Телекинез"

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Я еще до конца не закончил перепроверку и чистку заклинания, но (благодаря помощи Saturas-a) удалось довести до ума основную механику. Выкладываю небольшой ролик в надежде услышать, что надо подправить. С эффектами я не заморачивался вообще. Надеюсь на днях закончить и написать развернутую инструкцию.
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Re: создание заклинание телекинеза

Вполне себе ничего) Но есть один баг(правда заметить сложно, но есть)
Когда предмет к себе подвигаешь, и вовремя не прекратить каст, то предмет может оказатся в "Центре" гг, что чревато тем что гг просто не сможет сдвинутся с места без марвина.

Bump: А по сути, респект) на днях свой закончу на г2ексте)
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Re: создание заклинание телекинеза

Saturas, у меня такого бага нету - заклинание останавливается автоматически, когда расстояние между ГГ и предметом достигает 150-ти;)
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Re: создание заклинание телекинеза

аа, тогда все ок)

Bump: Тогда советуЮ сделать чтобы хоть чуточку быстрее предмет двигался к гг)
А то сильно уж медленно) ману можно всю спалить)
 

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
Re: создание заклинание телекинеза

George_M,
Красота! Ждем инструкцию :)
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Re: создание заклинание телекинеза

Myxomop, инструкции будут на днях.

Saturas, у меня сейчас стоит 1 мана на 100 расстояния - при максимуме в 5000 съест лишь 50, а скорость увеличить конечно стоит;)
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Re: создание заклинание телекинеза

Выкладываю обещанную инструкцию по созданию скриптового заклинания телекинеза для Готики2 с возможностью компиляции готиксорсером. Как я уже писал, с эффектами мне было лень возиться, поэтому здесь используется покореженное заклинание ледяного копья. Учитывая существующие мануалы, не думаю, что для кого-то будет проблемой создать отдельное заклинание.
Выкладываемую версию я протестил и постарался предусмотреть защиту на возможные баги, но учитывая, что скриптингом под вторую Готику я никогда не занимался (я и под первую то по сути не занимался ;) ), да и саму ее последний раз проходил несколько лет назад, мог что-то пропустить, поэтому буду благодарен за выловленные ошибки и постараюсь их исправить. Да, чуть не забыл: это все для версии Готики2НВ 2.6, на голде без фикса приводит к вылету.
Для работы нам понадобится старая версия скриптового пакета Икарус (новая слишком специфически использует работу движка и сорсер с ней помирить крайне проблематично) – ее можно найти в тексте обсуждения на немецком воге, классы двигателя и константы желательно брать из последний версий пакета: http://forum.worldofplayers.de/forum/showthread.php?t=969446 , а также пакет функций для работы с переменными типа float в представлении 32 bit IEEE 754: http://forum.worldofplayers.de/forum/showthread.php?t=500080
На всякий случай, выкладываю используемую мной подборку (классы oCNpc, oCItem, oCGame, oWorld, константы, Икарус и Floats32) – их желательно вставить поближе к началу *.src файла: Посмотреть вложение Ikarus_partial.rar. Икарус урезан – есть только необходимые функции, в которые при потребности были внесены правки для перевариваемости сорсером.

Приступим.
Для начала нам надо предоставить возможность заклинаниям ловить предмет в фокус. Для этого меняем в instance Focus_Magic(C_Focus) значение item_prio с -1 на 0.
Можно переходить к созданию инстанции самого заклинания. Сразу остановлюсь на двух моментах. Первое: как только спелы начинают брать в фокус предметы, двиг подкидываем в нагрузку известный по первой Готике баг: если при зажатой ЛК спрятать руну/свиток, то быстрым кликом все той же ЛК можно подобрать предмет на любом расстоянии. Как это убрать, я подробно описывал в теме по лечению багов в Г1, так что детально останавливаться не буду. Второе: для плавного движения предмета нам понадобится цикл с таймером. В случае создания заклинания наилучший подобный цикл сама функция Spell_Logic_нашезаклинание, возвращающая SPL_NEXTLEVEL: период отработки будет задаваться соотношение двух величин - time_per_mana и маны, необходимой для перехода на следующий уровень. Итак, имеем:
Код:
[COLOR=Blue]//стоимость перехода на следующий уровень[/COLOR]
  const int STEP_Icelance=1;
[COLOR=Blue]//счетчик цикла[/COLOR]
  var int stage;
[COLOR=Blue]//сбивание фокуса при убирании свитка[/COLOR]
  func int Spell_Icelance_focus_remover()
  {
              var oCNpc Npc; Npc = Hlp_GetNpc( hero );
              Npc.focus_vob=0;
[COLOR=Blue]//подстраховочное обнуление счетчика[/COLOR]
              stage=0;
              return false; 
  };
   instance Spell_Icelance(C_Spell_Proto)
  {
              time_per_mana       = 30;
              spelltype   = SPELL_NEUTRAL;
              targetCollectRange = 5000; 
              targetCollectAlgo    = TARGET_COLLECT_FOCUS; 
[COLOR=Blue]//чтобы ловило предметы[/COLOR]
              targetCollectType   = TARGET_TYPE_ITEMS; 
[COLOR=Blue]//сбивание фокуса при убирании свитка[/COLOR]
              canTurnDuringInvest   = Spell_Icelance_focus_remover();
              canChangeTargetDuringInvest = false;
};
Пришла очередь тела заклинания. Ассоциируем instance oCItem_Telekinesis (oCItem) с нашим предметом (ссылка на него хранится в Npc.focus_vob) с помощью функции MEM_AssignInst(temp, Npc.focus_vob). Для компиляции в сорсере используем промежуточную переменную с переопределенным типом, которую для компиляции нужно дописать в файл GothicSourcer/ System/RedefinedLocalVariable.dsc следующим образом: int# Spell_Logic_Icelance.temp; (сразу советую дописать туда же int# MEM_InitGlobalInst.game; - она используется в исправленном Икарусе):
Код:
var int temp;
temp = oCItem_Telekinesis;
MEM_AssignInst (temp, Npc.focus_vob);
Для расчета шага движения используем следующие функции из Floats32 (без них никак – Даэдалус с флотами не дружит):
аddf – сумма двух float;
subf - разница двух float;
divf – отношение двух float;
mkf – делает из простого int равное ему, но записанное в формате 32 bit IEEE 754.
Координаты кастера и предмета содержатся в _zCVob_trafoObjToWorld соответствующих классов. Данная переменная – массив из 16 элементов сделанный из матрицы 4х4. Последняя строчка пустая, а первые три по столбцам содержат 3 вектора ориентации и координату VOB-а, т.е. нас интересуют элементы [3],[7] и [11]. Не забывайте о путанице с Y и Z – вертикаль в [7]. Еще один важный момент – при движении надо менять координаты как предмета в _zCVob_trafoObjToWorld, так и координаты bbox3D в _zCVob_bbox3D_mins и _zCVob_bbox3D_maxs, т.к. они задаются не в относительной, а в абсолютной системе координат. Теперь все это собираем вместе. Дополнительно вводим счетчик шагов – с его помощью можно регулировать потребление маны, а заодно и задавать алгоритм движения на разных стадиях заклинания (не забываем его обнулить, заодно желательно добавить для надежности запасное обнуление в функцию сбивания фокуса – неизвестно как поведет себя двиг игры при избиении кастера в неподходящий момент). Сейчас в коде подстраховочная начальная стадия движения, чтобы предметы не проваливались под поверхность мира – грубый вариант, подымает на высоту bbox3D. Можно добавить просто постепенное поднятие первые n шагов движения. Советую подганять под потребности мода – если предметы прятать под потолком пещеры, поднятие нежелательно.
Код:
instance oCItem_Telekinesis (oCItem);
var int step_x;
var int step_y;
var int step_z;
var int numb_of_steps;
[COLOR=Blue]//функция движения предмета[/COLOR]
func void new_Telekinesis ()
{
   oCItem_Telekinesis._zCVob_trafoObjToWorld[3]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[3],step_x);   
   oCItem_Telekinesis._zCVob_trafoObjToWorld[7]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[7],step_z);   
   oCItem_Telekinesis._zCVob_trafoObjToWorld[11]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[11],step_y);
   oCItem_Telekinesis._zCVob_bbox3D_mins[0]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[0],step_x);
   oCItem_Telekinesis._zCVob_bbox3D_mins[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[1],step_z);
   oCItem_Telekinesis._zCVob_bbox3D_mins[2]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[2],step_y);
   oCItem_Telekinesis._zCVob_bbox3D_maxs[0]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[0],step_x);
   oCItem_Telekinesis._zCVob_bbox3D_maxs[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],step_z);
   oCItem_Telekinesis._zCVob_bbox3D_maxs[2]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[2],step_y);
[COLOR=Blue]//наложение эффекта[/COLOR]
  Wld_PlayEffect("spellFX_ItemAusbuddeln",oCItem_Telekinesis,oCItem_Telekinesis,0,0,0,FALSE);
};

func int Spell_Logic_Icelance(var int manaInvested)
{
  var oCNpc Npc; Npc = Hlp_GetNpc( self );
  if (stage==0)
  {
[COLOR=Blue]//привязка предмета в фокусе к инстанции oCItem_Telekinesis       [/COLOR]                    
  var int temp;
  temp = oCItem_Telekinesis;
  MEM_AssignInst (temp, Npc.focus_vob);
[COLOR=Blue]//расчет размера сдвига по осям исходя из шага в 10 единиц[/COLOR]
  numb_of_steps=Npc_GetDistToItem(self, oCItem_Telekinesis)/10;
  step_x=divf(subf(Npc._zCVob_trafoObjToWorld[3],oCItem_Telekinesis._zCVob_trafoObjToWorld[3]),mkf(numb_of_steps));
  step_z=divf(subf(Npc._zCVob_trafoObjToWorld[7],oCItem_Telekinesis._zCVob_trafoObjToWorld[7]),mkf(numb_of_steps));
  step_y=divf(subf(Npc._zCVob_trafoObjToWorld[11],oCItem_Telekinesis._zCVob_trafoObjToWorld[11]),mkf(numb_of_steps));
  };[COLOR=Blue]
//подстраховочная проверка на расстояние, чтобы не произошло наложение анимации перехода в состояние кастования и убирания свитка в конце[/COLOR]
  if(self.attribute[ATR_MANA] < STEP_Icelance)||((stage==0)&(Npc_GetDistToItem(self, oCItem_Telekinesis)<180))
  {
    return SPL_DONTINVEST;
  };
  if(manaInvested <= STEP_Icelance)
  {
    return SPL_STATUS_CANINVEST_NO_MANADEC;
  }
  else if (manaInvested > STEP_Icelance)
  {[COLOR=Blue]
//регулировка потребления маны – при таких значениях 1 мана на 10 циклов -100 единиц расстояния    [/COLOR]            
  if ((stage-1)%10==0)
  {
   self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - STEP_Icelance;
  };
  if(self.attribute[ATR_MANA] < 0)
  {
   self.attribute[ATR_MANA] = 0;
  };
[COLOR=Blue]//автоматическая остановка при приближении предмета[/COLOR]
   if (Npc_GetDistToItem(self, oCItem_Telekinesis)<150)
   {
[COLOR=Blue]//при остановке каста закинет в Spell_ProcessMana_Release  [/COLOR]                             
   return SPL_STATUS_CANINVEST_NO_MANADEC;
   };
[COLOR=Blue]//подстраховочная стадия движения[/COLOR]
   if (stage==0)
   {
    var int start_z;
    start_z=subf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],oCItem_Telekinesis._zCVob_bbox3D_mins[1]);
    oCItem_Telekinesis._zCVob_trafoObjToWorld[7]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[7],start_z);
    oCItem_Telekinesis._zCVob_bbox3D_mins[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[1],start_z);
    oCItem_Telekinesis._zCVob_bbox3D_maxs[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],start_z);
    Wld_PlayEffect("spellFX_ItemAusbuddeln",oCItem_Telekinesis,oCItem_Telekinesis,0,0,0,FALSE);
   };
[COLOR=Blue]//вызов функции сдвига[/COLOR]
   new_Telekinesis();
   stage+=1;
   return SPL_NEXTLEVEL;
  };
};
Теперь осталось только «уронить» подтянутый предмет на землю. Для этого нам понадобится класс двига oWorld – функция его привязке к инстанции MEM_World (немного подправленная) MEM_InitGlobalInst() содержится в пакете Икарус – ее желательно запихнуть в функцию инициализации мира при загрузке сейва, если пакет скриптов планируется использовать не только для этого заклинания. Далее делаем следующее: включаем «физику» нашему предмету, отключаем режим «sleep» и заносим в activeVobList (содержит ссылки на все VOB-ы, физика/AI которых отслеживается двигом). Еще надо не забыть убрать из инвентаря использованный свиток – т.к. заклинание вроде как не кастуется, двиг за нас этого не сделает. Полученный код добавляем в Spell_ProcessMana_Release – именно к ней обратится наше заклинание при остановке вкачивания маны:
Код:
func int Spell_ProcessMana_Release(var int manaInvested)
{
              ...
  if(activeSpell == SPL_IceLance)
  {
    if (stage>0)
    {
     var oCNpc Npc; Npc = Hlp_GetNpc( self );
     MEM_InitGlobalInst();
[COLOR=Blue]//включаем физику[/COLOR]
     oCItem_Telekinesis._zCVob_bitfield [0] = oCItem_Telekinesis._zCVob_bitfield [0] | zCVob_bitfield0_physicsEnabled;
[COLOR=Blue]//отключаем режим «sleep»[/COLOR]
     oCItem_Telekinesis._zCVob_bitfield[2]=oCItem_Telekinesis._zCVob_bitfield[2] | zCVob_bitfield2_sleepingMode;
[COLOR=Blue]//записываем в activeVobList
[/COLOR]     MEM_WriteInt(MEM_World.activeVobList_array+4*(MEM_World.activeVobList_numInArray), Npc.focus_vob);
[COLOR=Blue]//сообщаем, что activeVobList стал на 1 элемент длиннее[/COLOR]
     MEM_World.activeVobList_numInArray+=1;
[COLOR=Blue]//проверка на свиток/руну[/COLOR]
     if(Npc_GetActiveSpellIsScroll(self))
      {
[COLOR=Blue]//убираем свиток в инвентарь на случай если последний[/COLOR]
       AI_UnreadySpell(self);
[COLOR=Blue]//забираем свиток из инвентаря[/COLOR]
       Npc_RemoveInvItems(self,ItSc_Icelance,1);
      }
     else
      {
[COLOR=Blue]//просто чтобы заклинание при использовании свитка и руны выглядело одинаково[/COLOR]
       AI_UnreadySpell(self);
      };
     stage=0;
    };
    return SPL_SENDSTOP;
   };
              ...
};
Вроде ничего не забыл;)

P.S. Просьба к администрации - исправьте, плиз, опечатку в названии темы.
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Re: создание заклинание телекинеза

Отлично! Теперь я примерно понял как сделать аналог на г2екст...

Bump:
62.gif
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Код:
numb_of_steps=Npc_GetDistToItem(self, oCItem_Telekinesis)/10;
  step_x=divf(subf(Npc._zCVob_trafoObjToWorld[3],oCItem_Telekinesis._zCVob_trafoObjToWorld[3]),mkf(numb_of_steps));
  step_z=divf(subf(Npc._zCVob_trafoObjToWorld[7],oCItem_Telekinesis._zCVob_trafoObjToWorld[7]),mkf(numb_of_steps));
  step_y=divf(subf(Npc._zCVob_trafoObjToWorld[11],oCItem_Telekinesis._zCVob_trafoObjToWorld[11]),mkf(numb_of_steps));

Это мы получается уравниваем вектор разности чтоли?

Bump:
кстати, на г2ексте уже запилил телекинез, аналогично твоему.
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Это мы получается уравниваем вектор разности чтоли?
Не совсем понял формулировку... Это просто определяется размер шага по каждой из осей так чтобы вектор направления сохранялся, а расстояние между ГГ и итемом сокращалось на заданную величину (в данном случае порядка 10 единиц).

Bump:
крут!
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
ну это оно и есть кароче)
на днях как отдельный плагин на гекст скомпилю

Bump:
Код:
void Telekinesis()
{
	//--------------------------------
	//Движок заклинания Телекинез
	//		версия v0.8a
	//--------------------------------

	oCNpc*  hero   = oCNpc::GetHero();
	zCVob* pVob = hero->GetFocusVob();
	zCView* screen = zCView::GetScreen();
	zCModel* model = hero->GetModel();

		//если активна анимация S_FIBCAST, начинаем двигать предмет, иначе false
		if(pVob && model->IsAnimationActive("S_FIBCAST"))
		{
			zVEC3 pos = hero->GetPositionWorld();
			zVEC3 pitem = pVob->GetPositionWorld();
			x = (pos.f[0] - pitem.f[0]) / 500;
			z = (pos.f[1] - pitem.f[1]) / 500;
			y = (pos.f[2] - pitem.f[2]) / 500;
			pVob->SetPhysicsEnabled(0);
			pVob->SetPositionWorld(zVEC3(pitem.f[0] + x,pitem.f[1] + z,pitem.f[2] + y));
		}

}
вот так я сделал
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
Saturas, может сдвиг типа x = (pos.f[0] - pitem.f[0]) / 500; лучше делить не на 500, а на расстояние между ГГ и вобом, чтобы была одинаковая скорость движения, а не время доставки итема к цели?
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Да и так норм) Так по моему даже кошернее)
я скорее всего этот параметр завяжу какойнить атрибут гг)

Bump: Пока итем далеко движется быстро, а по приближении к гг медленно=)

Bump: на днях оформлю плагином

Bump: Хотя можно и так
Код:
			x = (pos.f[0] - pitem.f[0]) / hero->GetDistanceToVob(*pVob);
			z = (pos.f[1] - pitem.f[1]) / hero->GetDistanceToVob(*pVob);
			y = (pos.f[2] - pitem.f[2]) / hero->GetDistanceToVob(*pVob);
 

redleha


Модостроитель
Регистрация
26 Фев 2008
Сообщения
735
Благодарности
665
Баллы
245
Товарищи, кто занимается плагинами, есть вопрос.
Есть ли нормальный способ реализовать перемещение вобов с помощью телекинеза?
Я пока сделал навскидку один способ- связка (итем + мобси-сундук), но он извратный и имеет ряд ограничений:
1) итем можно поднять, причём напару с сундуком
2) при закле перемещается итем, а сундук уже телепортируется за ним в конце.
 

redleha


Модостроитель
Регистрация
26 Фев 2008
Сообщения
735
Благодарности
665
Баллы
245
Что же, товарищи, перемещение сундуков-то я сделал, но работает тоже корявенько, само перемещение то срабатывает, то срабатывает после сохранения игры :D
Сам механизм как из заклинания телепорта, но, чтобы цель ловилась в фокус, изменил вот что:
instance Focus_Magic(C_Focus)
{
...
mob_prio = 0;
};
И при вынимании заклинания, ловли в фокус, можно нажимать быструю клавишу, к которой привязана функция.
Если кто поможет, буду рад, ибо не имел ещё тесных контактов с пакетом Икаруса.
 

George_M

Участник форума
Регистрация
17 Дек 2010
Сообщения
692
Благодарности
18
Баллы
255
redleha, сейчас времени нет проверять, но на вскидку пришла идея. Не пробовал в битфилде моба ему свойство moveable добавлять?
Код:
const int oCMob_bitfield_moveable       = ((1 <<  1) - 1) << 25;
 

redleha


Модостроитель
Регистрация
26 Фев 2008
Сообщения
735
Благодарности
665
Баллы
245
George_M, я проверю, но вообще это свойство выставляется и в спейсере, и я этот флаг ставил сундуку там изначально тоже.
 

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
George_M,
В телекинезе redleha обнаружил фатальный баг приводящий к вылету игры, если используется последний свиток. Общими усилиями баг удалось побороть.

К телу закла был добавлен Spell_Cast_xxx и в него перенесено все (за исключением принудительного удаления свитка) что было в Spell_ProcessMana_Release. В самом же Spell_ProcessMana_Release теперь выглядит так

Код:
[COLOR="darkred"]  if(activeSpell == SPL_Telekinesis)
  {
   return SPL_SENDCAST;
  };[/COLOR]

при передаче в Spell_Cast_xxx последний свиток удаляется движком игры без вылета.
Также убран AI_UnreadySpell(self); - движек в Spell_Cast_xxx также сам нормально убирает заклинание.

Переработанный телекинез с основными правками
Редакция от 22.05.2012

Код:
const int SPL_Cost_Telekinesis = 1;
const int STEP_Telekinesis = 1;
var int stage;
//счетчик цикла
//var int stage;
//сбивание фокуса при убирании свитка
func int Spell_Telekinesis_focus_remover()
{
  var oCNpc Npc; Npc = Hlp_GetNpc( hero );
  Npc.focus_vob=0;
//подстраховочное обнуление счетчика
  stage=0;
  return false; 
};
instance oCItem_Telekinesis(oCItem);
var int step_x;
var int step_y;
var int step_z;
var int numb_of_steps;
//функция движения предмета
func void new_Telekinesis ()
{
  oCItem_Telekinesis._zCVob_trafoObjToWorld[3]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[3],step_x);   
  oCItem_Telekinesis._zCVob_trafoObjToWorld[7]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[7],step_z);   
  oCItem_Telekinesis._zCVob_trafoObjToWorld[11]=addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[11],step_y);
  oCItem_Telekinesis._zCVob_bbox3D_mins[0]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[0],step_x);
  oCItem_Telekinesis._zCVob_bbox3D_mins[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[1],step_z);
  oCItem_Telekinesis._zCVob_bbox3D_mins[2]=addf(oCItem_Telekinesis._zCVob_bbox3D_mins[2],step_y);
  oCItem_Telekinesis._zCVob_bbox3D_maxs[0]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[0],step_x);
  oCItem_Telekinesis._zCVob_bbox3D_maxs[1]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],step_z);
  oCItem_Telekinesis._zCVob_bbox3D_maxs[2]=addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[2],step_y);
  //наложение эффекта
  /*
  Wld_PlayEffect("spellFX_ItemAusbuddeln",oCItem_Telekinesis,oCItem_Telekinesis,0,0,0,FALSE);
  */
};

instance Spell_Telekinesis(C_Spell_Proto)
{
	time_per_mana = 30;
	spelltype = SPELL_NEUTRAL;
	targetCollectRange = 10000; 
	targetCollectAlgo = TARGET_COLLECT_FOCUS;
	targetCollectType = TARGET_TYPE_ITEMS;
	canTurnDuringInvest = Spell_Telekinesis_focus_remover();
	canChangeTargetDuringInvest = false;
};
func int Spell_Logic_Telekinesis(var int manaInvested)
{
	var oCNpc Npc; Npc = Hlp_GetNpc(self);
	if(stage == 0)
	{
		//привязка предмета в фокусе к инстанции oCItem_Telekinesis
		var int temp;
		temp = oCItem_Telekinesis;
		MEM_AssignInst(temp, Npc.focus_vob);
		//расчет размера сдвига по осям исходя из шага в 10 единиц
		numb_of_steps = Npc_GetDistToItem(self, oCItem_Telekinesis)/10;
		step_x = divf(subf(Npc._zCVob_trafoObjToWorld[3],oCItem_Telekinesis._zCVob_trafoObjToWorld[3]),mkf(numb_of_steps));
		step_z = divf(subf(Npc._zCVob_trafoObjToWorld[7],oCItem_Telekinesis._zCVob_trafoObjToWorld[7]),mkf(numb_of_steps));
		step_y = divf(subf(Npc._zCVob_trafoObjToWorld[11],oCItem_Telekinesis._zCVob_trafoObjToWorld[11]),mkf(numb_of_steps));
	};
	//подстраховочная проверка на расстояние, чтобы не произошло наложение анимации перехода в состояние кастования и убирания свитка в конце
	if((self.attribute[ATR_MANA] < STEP_Telekinesis) || ((stage==0) && (Npc_GetDistToItem(self, oCItem_Telekinesis) < 180)))
	{
		return SPL_DONTINVEST;
	};
	if(manaInvested <= STEP_Telekinesis)
	{
		return SPL_STATUS_CANINVEST_NO_MANADEC;
	}
	else if(manaInvested > STEP_Telekinesis)
	{
		//регулировка потребления маны – при таких значениях 1 мана на 10 циклов -100 единиц расстояния                
		if((stage - 1) % 10 == 0)
		{
			self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - STEP_Telekinesis;
		};
		if(self.attribute[ATR_MANA] < 0)
		{
			self.attribute[ATR_MANA] = 0;
		};
		//автоматическая остановка при приближении предмета
		if(Npc_GetDistToItem(self, oCItem_Telekinesis) < 150)
		{
			//при остановке каста закинет в Spell_ProcessMana_Release
			return SPL_SENDCAST;//SPL_STATUS_CANINVEST_NO_MANADEC;
		};
		//подстраховочная стадия движения
		if(stage==0)
		{
			var int start_z;
			start_z = subf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],oCItem_Telekinesis._zCVob_bbox3D_mins[1]);
			oCItem_Telekinesis._zCVob_trafoObjToWorld[7] = addf(oCItem_Telekinesis._zCVob_trafoObjToWorld[7],start_z);
			oCItem_Telekinesis._zCVob_bbox3D_mins[1] = addf(oCItem_Telekinesis._zCVob_bbox3D_mins[1],start_z);
			oCItem_Telekinesis._zCVob_bbox3D_maxs[1] = addf(oCItem_Telekinesis._zCVob_bbox3D_maxs[1],start_z);
			Wld_PlayEffect("spellFX_ItemAusbuddeln",oCItem_Telekinesis,oCItem_Telekinesis,0,0,0,FALSE);
		};
		//вызов функции сдвига
		new_Telekinesis();
		stage += 1;
		return SPL_NEXTLEVEL;
	}
	else if(Npc_GetDistToItem(self, oCItem_Telekinesis) < 150)
	{
		return SPL_SENDCAST;
	};
	return SPL_STATUS_CANINVEST_NO_MANADEC;
};

[COLOR="DarkRed"]func void Spell_Cast_Telekinesis()
{
	var oCNpc Npc; Npc = Hlp_GetNpc(self);
	MEM_InitGlobalInst();
	//включаем физику
	oCItem_Telekinesis._zCVob_bitfield[0] = oCItem_Telekinesis._zCVob_bitfield[0] | zCVob_bitfield0_physicsEnabled;
	//отключаем режим «sleep»
	oCItem_Telekinesis._zCVob_bitfield[2] = oCItem_Telekinesis._zCVob_bitfield[2] | zCVob_bitfield2_sleepingMode;
	//записываем в activeVobList
	MEM_WriteInt(MEM_World.activeVobList_array + 4*(MEM_World.activeVobList_numInArray),Npc.focus_vob);
	//сообщаем, что activeVobList стал на 1 элемент длиннее
	MEM_World.activeVobList_numInArray += 1;
	stage = 0;
	self.aivar[AIV_SelectSpell] += 1;
};[/COLOR]
 

Saturas


Модостроитель
Регистрация
11 Фев 2009
Сообщения
2.512
Благодарности
1.334
Баллы
315
Что же, товарищи, перемещение сундуков-то я сделал, но работает тоже корявенько, само перемещение то срабатывает, то срабатывает после сохранения игры :D
Сам механизм как из заклинания телепорта, но, чтобы цель ловилась в фокус, изменил вот что:
instance Focus_Magic(C_Focus)
{
...
mob_prio = 0;
};
И при вынимании заклинания, ловли в фокус, можно нажимать быструю клавишу, к которой привязана функция.
Если кто поможет, буду рад, ибо не имел ещё тесных контактов с пакетом Икаруса.
Дык, я могу, но на ексте( а на чем же еще?);)

хотя... от екста там одно название, ибо от либы g2ext.dll я уже давно отказался, ибо УГ, от него там осталось всего ничего)
 
Сверху Снизу