Mod Обработка эвентов криттера в скриптовом классе.

Автор темы #1
Дата рег
19 Фев 2011
Сообщения
197
Симпатии
72
Данный мод позволет обрабатывать эвенты криттера в своем скриптовом классе без дополнительных манипуляций и синхронизаций. Так-же он может служить расширителем класса Critter скриптовым классом, но в связи с огромным количеством неиспользуемых переменных в структуре Critter это не так актуально ( хотя и бывает нужно для единичных ситуаций ).

Все что нужно сделать, это вызвать функцию ExpansionCritterInit( Critter& cr, bool isFirst, string& nameClass ) в скрипте инициализации криттера, с передачей в виде аргументов самого криттера, признак того создан криттер или загружен и имя нашего класса обработчика. Все эвенты объявятся автоматически, в зависимости от объявленных функций внутри класса ( если вам нужен айдле, объявляйте внутри класса функцию void Idle(Critter& cr ), и он будет назначен обработчиком ). Все переменные внутри класса будут сохранены на время работы сервера, и всегда будут актуальны для нашего криттера. (сохранение\синхронизацию данных после рестартов оставляю на вашей совести, если оно действительно нужно, могу лишь посоветовать использовать класс file, или AnyData ( во время остановки сервера ( вызов Finish с delete == false ) в ану дата сохранять не получится, предупреждаю сразу ) )
Единственное за чем необходимо следить, так это за эвентом CRITTER_EVENT_FINISH, по умолчанию он будет объявлен автоматически, внутри длл, даже если у вас нету функции обработчика в классе. Но если вы перегрузите этот эвент, то вызывайте функцию void ExpansionCritterFinish(Critter& cr, bool deleted) внутри своего обработчика ( естественно только для расширеных криттеров ), это необходимо для подсчета ссылок.

const bool Critter::IsExpansion // Переменная криттера, регистрируется в длл для всего скриптого движка, в точке входа. Указывает на то расширен криттер, или нет.

Функции обработчики:
EXPORT void ExpansionCritterInit( Critter& cr, bool first, ScriptString& className, bool autoEvent = true );
EXPORT void ExpansionCritterInit_IgnoreEvents( Critter& cr, bool first, ScriptString& className, ScriptArray& events );
EXPORT void ExpansionCritterInit_IgnoreEvent( Critter& cr, bool first, ScriptString& className, int event );

EXPORT void ExpansionCritterFinish(Critter& cr, bool deleted);
EXPORT void ExpansionCritterDead(Critter& cr, Critter* killer);
EXPORT void ExpansionCritterIdle(Critter& cr);
EXPORT void ExpansionCritterRespawn(Critter& cr);
EXPORT void ExpansionCritterKnockout(Critter& cr);
EXPORT bool ExpansionCritterAttack( Critter& cr, Critter* target );
EXPORT bool ExpansionCritterAttacked( Critter& cr, Critter* attacker );
EXPORT void ExpansionCritterStealing(Critter& cr, Critter& thief, bool success, Item& item, uint count);
EXPORT void ExpansionCritterShowCritter(Critter& cr, Critter& showCrit);
EXPORT void ExpansionCritterShowCritter1(Critter& cr, Critter& showCrit);
EXPORT void ExpansionCritterShowCritter2(Critter& cr, Critter& showCrit);
EXPORT void ExpansionCritterShowCritter3(Critter& cr, Critter& showCrit);
EXPORT void ExpansionCritterHideCritter(Critter& cr, Critter& hideCrit);
EXPORT void ExpansionCritterHideCritter1(Critter& cr, Critter& hideCrit);
EXPORT void ExpansionCritterHideCritter2(Critter& cr, Critter& hideCrit);
EXPORT void ExpansionCritterHideCritter3(Critter& cr, Critter& hideCrit);
EXPORT void ExpansionCritterShowItemOnMap(Critter& cr, Item& showItem, bool added, Critter* dropper);
EXPORT void ExpansionCritterChangeItemOnMap(Critter& cr, Item& item);
EXPORT void ExpansionCritterHideItemOnMap(Critter& cr, Item& hideItem, bool removed, Critter* picker);
EXPORT void ExpansionCritterMessage(Critter& cr, Critter& fromCr, int message, int value);
EXPORT bool ExpansionCritterUseItem(Critter& cr, Item& item, Critter* onCritter, Item* onItem, Scenery* onScenery);
EXPORT bool ExpansionCritterUseSkillOnMe(Critter& cr, Critter& whoUse, int skill);
EXPORT bool ExpansionCritterUseSkill(Critter& cr, int skill, Critter* onCritter, Item* onItem, Scenery* onScenery);
EXPORT bool ExpansionCritterUseItemOnMe(Critter& cr, Critter& whoUse, Item& item);
EXPORT void ExpansionCritterDropItem(Critter& cr, Item& item);
EXPORT void ExpansionCritterMoveItem(Critter& cr, Item& item, uint8 fromSlot);
EXPORT void ExpansionCritterSmthDead(Critter& cr, Critter& fromCr, Critter* killer);
EXPORT void ExpansionCritterSmthTurnBasedProcess(Critter& cr, Critter& fromCr, Map& map, bool beginTurn);
EXPORT void ExpansionCritterTurnBasedProcess(Critter& cr, Map& map, bool beginTurn);
EXPORT bool ExpansionCritterGlobalInvate(Critter& cr, Item* car, uint encounterDescriptor, int combatMode, uint& mapId, uint16& hexX, uint16& hexY, uint8& dir);
EXPORT bool ExpansionCritterGlobalProcess(Critter& cr, int type, Item* car, float& x, float& y, float& toX, float& toY, float& speed, uint& encounterDescriptor, bool& waitForAnswer);
EXPORT bool ExpansionCritterTalk(Critter& cr, Critter& talkCr, bool attach, uint talkCount);
EXPORT bool ExpansionCritterBarter(Critter& cr, Critter& barterCr, bool attach, uint barterCount);
EXPORT int ExpansionCritterPlaneRun(Critter& cr, NpcPlane& plane, int reason, uint& result0, uint& result1, uint& result2);
EXPORT int ExpansionCritterPlaneEnd(Critter& cr, NpcPlane& plane, int reason, Critter* someCr, Item* someItem);
EXPORT int ExpansionCritterPlaneBegin(Critter& cr, NpcPlane& plane, int reason, Critter* someCr, Item* someItem);
EXPORT void ExpansionCritterSmthKnockout(Critter& cr, Critter& fromCr, uint anim2begin, uint anim2idle, uint anim2end, uint lostAp, uint knockDist);
EXPORT void ExpansionCritterSmthMoveItem(Critter& cr, Critter& fromCr, Item& item, uint8 fromSlot);
EXPORT void ExpansionCritterSmthDropItem(Critter& cr, Critter& fromCr, Item& item);
EXPORT void ExpansionCritterSmthUseSkill(Critter& cr, Critter& fromCr, int skill, Critter* onCritter, Item* onItem, Scenery* onScenery);
EXPORT void ExpansionCritterSmthUseItem(Critter& cr, Critter& fromCr, Item& item, Critter* onCritter, Item* onItem, Scenery* onScenery);
EXPORT void ExpansionCritterSmthAttacked(Critter& cr, Critter& fromCr, Critter& attacker);
EXPORT void ExpansionCritterSmthAttack(Critter& cr, Critter& fromCr, Critter& target);
EXPORT void ExpansionCritterSmthStealing(Critter& cr, Critter& fromCr, Critter& thief, bool success, Item& item, uint count);

EXPORT int ExpansionCritterRunScript( Critter& cr, ScriptString& funcName, int& p0, int& p1, int& p2 );
EXPORT int ExpansionCritterRunScriptUnknown( Critter& cr, ScriptString& funcName, asIScriptObject& p0 );
EXPORT uint Map_GetExpansionCritters( Map& map, Critter@[]@+ array, string@+ typeName );

CRITTER_EVENT_DEAD
void Dead(Critter& cr, Critter@ killer)
CRITTER_EVENT_IDLE
void Idle(Critter& cr)
CRITTER_EVENT_RESPAWN
void Respawn(Critter& cr)
CRITTER_EVENT_KNOCKOUT
void Knockout(Critter& cr)
CRITTER_EVENT_ATTACK
bool Attack( Critter& cr, Critter@ target )
CRITTER_EVENT_ATTACKED
bool Attacked( Critter& cr, Critter@ attacker )
CRITTER_EVENT_STEALING
void Stealing(Critter& cr, Critter& thief, bool success, Item& item, uint count)
CRITTER_EVENT_HIDE_CRITTER
void HideCritter(Critter& cr, Critter& hideCrit)
CRITTER_EVENT_HIDE_CRITTER_X ( X = 1-3 )
void HideCritterX(Critter& cr, Critter& hideCrit)
CRITTER_EVENT_SHOW_ITEM_ON_MAP
void ShowItemOnMap(Critter& cr, Item& showItem, bool added, Critter@ dropper)
CRITTER_EVENT_CHANGE_ITEM_ON_MAP
void ChangeItemOnMap(Critter& cr, Item& item)
CRITTER_EVENT_HIDE_ITEM_ON_MAP
void HideItemOnMap(Critter& cr, Item& hideItem, bool removed, Critter@ picker)
CRITTER_EVENT_MESSAGE
void Message(Critter& cr, Critter& fromCr, int message, int value)
CRITTER_EVENT_USE_ITEM
bool UseItem(Critter& cr, Item& item, Critter@ onCritter, Item@ onItem, Scenery@ onScenery)
CRITTER_EVENT_SHOW_CRITTER
void ShowCritter(Critter& cr, Critter& showCrit)
CRITTER_EVENT_SHOW_CRITTER_X ( X = 1-3 )
void ShowCritterX(Critter& cr, Critter& showCrit)
CRITTER_EVENT_USE_SKILL_ON_ME
bool UseSkillOnMe(Critter& cr, Critter& whoUse, int skill)
CRITTER_EVENT_USE_SKILL
bool UseSkill(Critter& cr, int skill, Critter@ onCritter, Item@ onItem, Scenery@ onScenery)
CRITTER_EVENT_USE_ITEM_ON_ME
bool UseItemOnMe(Critter& cr, Critter& whoUse, Item& item)
CRITTER_EVENT_DROP_ITEM
void DropItem(Critter& cr, Item& item)
CRITTER_EVENT_MOVE_ITEM
void MoveItem(Critter& cr, Item& item, uint8 fromSlot)
CRITTER_EVENT_SMTH_DEAD
void SmthDead(Critter& cr, Critter& fromCr, Critter@ killer)
CRITTER_EVENT_SMTH_TURN_BASED_PROCESS
void SmthTurnBasedProcess(Critter& cr, Critter& fromCr, Map& map, bool beginTurn)
CRITTER_EVENT_TURN_BASED_PROCESS
void TurnBasedProcess(Critter& cr, Map& map, bool beginTurn)
CRITTER_EVENT_GLOBAL_INVITE
bool GlobalInvate(Critter& cr, Item@ car, uint encounterDescriptor, int combatMode, uint& mapId, uint16& hexX, uint16& hexY, uint8& dir)
CRITTER_EVENT_GLOBAL_PROCESS
bool GlobalProcess(Critter& cr, int type, Item@ car, float& x, float& y, float& toX, float& toY, float& speed, uint& encounterDescriptor, bool& waitForAnswer)
CRITTER_EVENT_TALK
bool Talk(Critter& cr, Critter& talkCr, bool attach, uint talkCount)
CRITTER_EVENT_BARTER
bool Barter(Critter& cr, Critter& barterCr, bool attach, uint barterCount)
CRITTER_EVENT_PLANE_RUN
int PlaneRun(Critter& cr, NpcPlane& plane, int reason, uint& result0, uint& result1, uint& result2)
CRITTER_EVENT_PLANE_END
int PlaneEnd(Critter& cr, NpcPlane& plane, int reason, Critter@ someCr, Item@ someItem)
CRITTER_EVENT_PLANE_BEGIN
int PlaneBegin(Critter& cr, NpcPlane& plane, int reason, Critter@ someCr, Item@ someItem)
CRITTER_EVENT_SMTH_KNOCKOUT
void SmthKnockout(Critter& cr, Critter& fromCr, uint anim2begin, uint anim2idle, uint anim2end, uint lostAp, uint knockDist)
CRITTER_EVENT_SMTH_MOVE_ITEM
void SmthMoveItem(Critter& cr, Critter& fromCr, Item& item, uint8 fromSlot)
CRITTER_EVENT_SMTH_DROP_ITEM
void SmthDropItem(Critter& cr, Critter& fromCr, Item& item)
CRITTER_EVENT_SMTH_USE_SKILL
void SmthUseSkill(Critter& cr, Critter& fromCr, int skill, Critter@ onCritter, Item@ onItem, Scenery@ onScenery)
CRITTER_EVENT_SMTH_USE_ITEM
void SmthUseItem(Critter& cr, Critter& fromCr, Item& item, Critter@ onCritter, Item@ onItem, Scenery@ onScenery)
CRITTER_EVENT_SMTH_ATTACKED
void SmthAttacked(Critter& cr, Critter& fromCr, Critter& attacker)
CRITTER_EVENT_SMTH_ATTACK
void SmthAttack(Critter& cr, Critter& fromCr, Critter& target)
CRITTER_EVENT_SMTH_STEALING
void SmthStealing(Critter& cr, Critter& fromCr, Critter& thief, bool success, Item& item, uint count)

Код:
#pragma bindfunc "void Critter::ExpansionInit( bool first, string&in className ) -> expasion_critter.dll ExpansionCritterInit"
#pragma bindfunc "int Critter::ExpansionCritterRunScript( string& funcName, int& p0, int& p1, int& p2 ) -> expasion_critter.dll ExpansionCritterRunScript"
#pragma bindfunc "int Critter::ExpansionCritterRunScript( string& funcName, ?&inout arg ) -> expasion_critter.dll ExpansionCritterRunScriptUnknown"
#pragma bindfunc "uint Map::GetExpansionCritters( Critter@[]@+ array, string@+ typeName ) -> expasion_critter.dll Map_GetExpansionCritters"
 
namespace TestExpansionCritter
{
uint LastId = 0;
uint CountBoss = 0;
}
void BotBossInit( Critter& cr, bool first )
{
cr.ExpansionInit(first, "BotBoss" );
}
void SecondBotInit( Critter& cr, bool first )
{
cr.ExpansionInit(first, "SecondBot" );
}
// ~run debug TestBotBoss 1 0 0
void TestBotBoss( Critter& player, int param, int param1, int )
{
Critter@ bot = null;
Critter@ botMemm = null;
if( param1 == 0 )
{
@ bot = player.GetMap().AddNpc(param, player.HexX, player.HexY-1, 5, null, null, "BotBossInit");
player.Say( SAY_NETMSG, "BotBossId = " + bot.Id );
TestExpansionCritter::LastId = bot.Id;
@ botMemm = bot.GetMap().AddNpc(param + 1, bot.HexX, bot.HexY-1, 5, null, null, "SecondBotInit");
int var0 = botMemm.Id, var1 = 0, var2 = 0;
bot.ExpansionCritterRunScript( "bool AddSecondBot(Critter& cr, int&inout id, int&inout, int&inout)", var0, var1, var2 );
@ botMemm = bot.GetMap().AddNpc(param + 1, bot.HexX, bot.HexY-2, 5, null, null, "SecondBotInit");
var0 = botMemm.Id;
bot.ExpansionCritterRunScript( "bool AddSecondBot(Critter& cr, int&inout id, int&inout, int&inout)", var0, var1, var2 );
@ botMemm = bot.GetMap().AddNpc(param + 1, bot.HexX, bot.HexY-3, 5, null, null, "SecondBotInit");
var0 = botMemm.Id;
bot.ExpansionCritterRunScript( "bool AddSecondBot(Critter& cr, int&inout id, int&inout, int&inout)", var0, var1, var2 );
 
any anyBot;
if( bot.ExpansionCritterRunScript( "bool GetMy( Critter& cr, any& bot )", anyBot ) == 0 )
{
BotBoss@ botRef = BotBoss();
anyBot.retrieve( botRef );
player.Say( SAY_NETMSG, "botRef Id = " + botRef.Id );
}
player.Say( SAY_NETMSG, "botRef Id = " + player.GetMap().GetExpansionCritters( null ,"SecondBot" ) );
 
}
else if( param1 == 1 )
{
@ bot = GetCritter( TestExpansionCritter::LastId );
int var0 = player.Id, var1 = 0, var2 = 0;
bot.ExpansionCritterRunScript( "bool CountingBots( Critter& cr, int& masterId, int&, int& )", var0, var1, var2 );
}
else if( param1 == 2 )
{
@ bot = GetCritter( TestExpansionCritter::LastId );
 
}
}
class SecondBot
{
SecondBot()
{
CritterId = 0;
@ Name = "None";
}
 
void Init( Critter& cr, bool )
{
CritterId = cr.Id;
@ Name = "SecondBot_"+CritterId;
Log( "SecondBot Init" );
}
 
bool GetMyName( Critter& cr, array<string@>& arr )
{
arr.insertLast( Name );
return true;
}
 
string@ Name;
uint CritterId;
}
class BotBoss
{
BotBoss()
{
CritterId = 0;
Id = 0;
Log( "BotBoss" );
}
 
void Init( Critter& cr, bool )
{
CritterId = cr.Id;
Id = ++TestExpansionCritter::CountBoss;
Log( "BotBoss Init" );
}
 
bool AddSecondBot(Critter& cr, int&inout id, int&inout, int&inout)
{
SecondBotIds.insertLast( uint( id ) );
Log( "Add second bot ("+id+")");
return true;
}
 
bool CountingBots( Critter& cr, int& masterId, int&, int& )
{
Critter@ master = GetCritter( masterId ), bot = null;
array<string@> str;
for( uint i = 0, iEnd = SecondBotIds.length(); i < iEnd; i++ )
{
@ bot = GetCritter( SecondBotIds[i] );
bot.ExpansionCritterRunScript( "bool GetMyName( Critter& cr, array<string@>& arr )", str );
}
master.Say( SAY_NETMSG, join( str, "\n" ));
return true;
}
 
void Finish( Critter& cr, bool )
{
Log( "BotBoss Finish " + CritterId );
}
 
void Dead(Critter& cr, Critter@ killer)
{
Log( "BotBoss Dead " + CritterId );
}
 
void Idle(Critter& cr )
{
Log( "BotBoss Idle " + CritterId );
}
 
void Respawn(Critter& cr )
{
Log( "BotBoss Respawn " + CritterId );
}
 
void Knockout(Critter& cr )
{
Log( "BotBoss Knockout " + CritterId );
}
 
bool Attack( Critter& cr, Critter@ target )
{
Log( "BotBoss Attack " + CritterId );
return true;
}
 
bool Attacked( Critter& cr, Critter@ attacker )
{
Log( "BotBoss Attacked " + CritterId );
return true;
}
 
void Stealing(Critter& cr, Critter& thief, bool success, Item& item, uint count)
{
Log( "BotBoss Stealing " + CritterId );
}
 
bool UseSkill(Critter& cr, int skill, Critter@ onCritter, Item@ onItem, Scenery@ onScenery)
{
Log( "BotBoss UseSkill " + CritterId );
return true;
}
 
bool UseItemOnMe(Critter& cr, Critter& whoUse, Item& item)
{
Log( "BotBoss UseItemOnMe " + CritterId );
return true;
}
 
void SmthDead(Critter& cr, Critter& fromCr, Critter@ killer)
{
Log( "BotBoss SmthDead " + CritterId );
if( valid( killer ) )
{
Log( "killer.Id = " + killer.Id );
}
}
 
bool GetMy( Critter& cr, any& getMy )
{
getMy.store( this );
return true;
}
 
array<uint> SecondBotIds;
uint CritterId;
uint Id;
}

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

Вложения

Последнее редактирование:
Автор темы #2
Дата рег
19 Фев 2011
Сообщения
197
Симпатии
72
Добавил возможность вызывать функции класса через криттера.
Для этого используйте функции:
EXPORT int ExpansionCritterRunScript( Critter& cr, ScriptString& funcName, int& p0, int& p1, int& p2 );
EXPORT int ExpansionCritterRunScriptArray( Critter& cr, ScriptString& funcName, ScriptArray& p0 );

Функции в классе должна выглядить как:
bool Func(Critter& cr, int&, int&, int&)
bool Func(Critter& cr, array&) - Тип массива задавайте сами.

funcName - имя декларации функции ( пример ExpansionCritterRunScript( cr, "bool GetMyName( Critter& cr, array<string@>& arr )", str ) )

Возвращают тип инт, в случае если для криттера нету класса расширителя вернет -3, если нету функции вернет -2, если функция вызвана с ошибками -1, если функция класса вернула true 0, если вернула false 1.

Обновил пример в первом посте, мод залил в первый пост.
 
Автор темы #3
Дата рег
19 Фев 2011
Сообщения
197
Симпатии
72
Добавлен таймаут на выполнение скриптов запущенных этой библиотекой( 1 секунда ), при превышении скрипт прекращает выполнение работы. Необходимо для защиты от зацикливания. ( У скриптов запущенных движком есть аналогичная защита )

Изменены функции:
int ExpansionCritterRunScriptArray( Critter& cr, ScriptString& funcName, ScriptArray& p0 );
заменена на
int ExpansionCritterRunScriptUnknown( Critter& cr, ScriptString& funcName, asIScriptObject& p0 );
Что позволяет получать\передавать любой тип в функцию.

void ExpansionCritterInit( Critter& cr, bool first, ScriptString& className );
изменена на
void ExpansionCritterInit( Critter& cr, bool first, ScriptString& className, bool autoEvent = true ); - где autoEvent при true назначает обработчики, при false нет ( только финиш )

Добавлены функции:
uint Map_GetExpansionCritters( Map& map, Critter@[]@+ array, string@+ typeName ) - позволяет получить криттеров с карты у которых имя класса расширителя равно typeName. Возвращает количество найденных криттеров. Массив дописывается с конца. Если array == null вернет количество без записи в массив. Если typeName == null, либо строка пустая, вернет всех криттеров с любым расширением.

void ExpansionCritterInit_IgnoreEvents( Critter& cr, bool first, ScriptString& className, ScriptArray& events ); - инициализирует расширитель для криттера, с установкой эвентов по декларации вашего класса. Массив events должен содержать эвенты которые следует игнорировать при автоназначении эвента.

void ExpansionCritterInit_IgnoreEvent( Critter& cr, bool first, ScriptString& className, int event ); - инициализирует расширитель для криттера, с установкой эвентов по декларации вашего класса. Переменная event должна содержать номер эвента который следует игнорировать при автоназначении эвента.

Обновленный мод в первом посте.
Обновил пример, добавил пример получения класса расширителя через криттера.
 
Последнее редактирование:
Автор темы #4
Дата рег
19 Фев 2011
Сообщения
197
Симпатии
72
Немного оптимизации, исправил утечку памяти при переопределении класса расширения ( не освобождал старый объект ).

Дополнительно резервирует верхние 44 верхние поля у Reserved22 ( хранит ссылки на функции, что убирает необходимость искать тип объекта и саму функцию типа для каждого вызова события ), и Reserved0.

Добавлена функция EXPORT bool IsClassExpansionCritter( Critter& cr, ScriptString* typeName ), позволяет узнать является ли класс typeName расширением для cr.
Время выполнения берется из FOnline->ScriptRunSuspendTimeout

Что-то еще.
 

Вложения

Автор темы #5
Дата рег
19 Фев 2011
Сообщения
197
Симпатии
72
Если сервер падал с дампом, то эта модификация не позволит серверу подняться. Чтобы этого избежать обнуляйте в глобальном обработчике critter_init зарезервированные поля ( через натив ).

cr.ReservedCE = 0;
cr.Reserved0 = 1;
cr.Reserved1[0] = 0;
for(uint i = 0; i < CRITTER_EVENT_MAX; i++)
cr.Reserved22[ 56 + i] = 0;