Post
by kotekzot » Tue, 8. Jan 08, 23:53
ULiX is the one who reverse engineered the game's mechanics relevant to ship capture, as well as the ware dropping, assasination mission ship generation and the rating chaging, i just read and understood them. here's the relevant procedure.
TSHIP.AttackedBy(Attacker, arg2) {
//arg2 - судя по контексту тип применяемого оружия
TSCRIPT.AttackedBy(Attacker,arg2);
if (Attacker) {
AttackerEv = SA_GetEventObject(Attacker);
if (AttackerEv && sh_Owner){
if (arg2 == 0 && (sh_Flags & 1)){ // если не использовано орудие
TCLIENT.NotifyCollisionWarn(0); // угроза столкновения уровня 0
} //L000BF866
if ((ga_PlayerShip != AttackerEv) && (arg2) && (SA_GetFlag2(arg2) & 0100h)){
//Если атакующий не корабль игрока, но использовано орудие, и орудие
//способно на захват, то
//при этом атакующим объектом становится корабль игрока, а атакующим - игрок, причем
//только если он в активном секторе. Это условие необходимо для проверки орудий кокпитов.
AttackerEv = ga_PlayerShip;
Attacker = ga_PlayerShip.GetObjectID(); //функция вернёт нуль, если объект не в активном секторе
} //L000BF8D4
AttackerOwner = AttackerEv.GetOwner(); // (loc2) Принадлежность атакующего
if (SE_IsClass(AttackerEv,2004){ //Атакующий объект является кораблем
if (AttackerEv == ga_PlayerShip) || (THIS.IsEnemy(AttackerEv)){
//Атакующий объект корабль игрока или враг
//L000BF922 -> L000BF934
if (AttackerOwner != sh_Owner){
// Атакующий и атакуемый не принадлежат одному владельцу
if !(arg2) || (SA_GetGroup(arg2) == AttackerOwner.GetGroup()) {
//для атаки не использовано орудие или ......................
//захват возможен только при данном
//условии (SA_GetGroup(arg2) == AttackerOwner.GetGroup())
//так как по следующему условию обязательно arg2 <> 0
//L000BF9A0
if (AttackerEv == ga_PlayerShip) && arg2 {
//Атакующий объект - карабль игрока и применяет орудие
//L000BF9CA:
if !(TCLIENT.GetClientState() & 0200h) &&
(sh_Owner <> ga_Player) && (sh_Owner <> ga_Races[18]){ // sh_Owner != Earth
//сброшен 9 бит во флаге статистики игрока,
//атакуемый не принадлежит игроку и землянам
if ((SE_Random(100) < 4) || (SA_GetType(arg2) <> 17){ //Ion Distructor
//Вот интересный момент. Если пользуемся ID то основное
//вычисления вероятности возможно с вероятностью 0.04.
//Если пользоваться не ID, то лишняя случайность отсекается
//Использование ID уменьшает общую вероятность захватить в 25 раз!!!
if (SA_GetShipTypeCockpitBody(sh_SubType) && !(sh_Flags & 0100b)){
//если есть кабина и разрешен захват данного корабля
Shield = SA_GetShield(sh_ObjectID);
LimShield = SA_GetMaxShield(sh_ObjectID);
Hull = SA_GetHul(sh_ObjectID);
MaxHull = SA_GetMaxHull(sh_ObjectID);
LimShield = LimShield / 100 // LimShield = MaxShield / 100
if (LimShild > 1000) LimShild = 1000;
//Минимальное значение щита, при котором
//будет проверяться вероятность капитулирования
// 1% от максимума, или 1000, если 1% превышает 1000 единиц.
if (Shield <= LimShield) && (Hull > 0) && (Hull < SE_Random(8) * MaxHull / 8) {
//Щиты меньше лимитного, а корпус поврежден и лежит в интервале от
//нуля до переменного случайного значения MaxHull * i/8,
//где i - целое в интервале от 0 до 7
//Максимальная целостность корпуса, при которой возможен захват 87%
if (ga_Player.GetAge() > sh_NextTakeoverChanceTime) {
//Время игры превышает время, когда даётся шанс на захват
if ((sh_TakeoverDelayTime > 300) &&
(ga_Player.GetAge() > (sh_NextTakeoverChanceTime + sh_TakeoverDelayTime)) {
//Задержка между шансами захватить больше 300 секунд, и
//время игры больше времени следующего шанса + задержка между шансами
sh_TakeoverDelayTime = 30; //Установить задержку в 30 секунд
// -> L000BFBFC
} //L000BFBD6 -> L000BFBEC
else {
sh_TakeoverDelayTime += sh_TakeoverDelayTime; //иначе, удвоить задержку
}
//L000BFBFC:
sh_NextTakeoverChanceTime = ga_Player.GetAge() + sh_TakeoverDelayTime;
//установить время следующего шанса захватить кораблик
ProbabilityCapture = 30 - this.GetPilotMorale();
//установить начальную вероятность захвата в 30% минус уровень марали атакуемого
// т.е. от 20 до 30%
if (AttackerEv.GetStrength() < this.GetStrength()){
//если сила атакующего меньше силы атакуемого
ProbabilityCapture -= 5;
//уменьшить вероятность прыжка на 5%
//сила находится как сумма Shileld + Hull + MaxLaserDamage
}
if (Hull <> 0){
//Если корпус не равен нулю
ProbabilityAdd = MaxHull / (Hull * 4);
if (ProbabilityOnHull > 10) ProbabilityOnHull = 10;
ProbabilityCapture += ProbabilityAdd;
//Добавочная вероятность, по побитому корпусу
//1% при целостности меньше 25%
//2% - меньше 12%
//3% - меньше 8%
//10% - меньше 2%
// Не стоящий учета параметр, главное, чтоб корпус был поврежден до
// состояния 87%, когда вообще появляется шанс захватить
} //L000BFC94
ProbabilityCapture -= sh_TakeoverDelayTime / 30;
//Уменьшение вероятности в зависимости от интервала ожидания между
//шансами захватить
//Возможные значения 1%, 2%, 4%, 8%, 16%, для 30, 60, 120, 240, 480 секунд задержки
//Что объясняет больший шанс захватить сразу, нежели спустя некоторое время
if (sh_Owner == ga_Races[7]){
//Раса корабля хаак. Расчет вероятности захвата хааков
//зависит от текущего боевого рейтинга.
//до 6 уровня захват хааков невозможен, и только на 30 уровне
//их можно захватывать наравне с другими кораблями
//Множитель (FightRank - 5) / 25
ProbabilityAdd = GetTitleFromFightRanking(ga_Player.GetFightRanking());
ProbabilityCapture *= (ProbabilityAdd - 5) / 25;
if (ProbabilityCapture < 0) ProbabilityCapture = 0;
//если получилось меньше нуля, приравнять к нулю
}//L000BFD06
//
if (ProbabilityCapture > SE_Random(100){
//Ну и, наконец, если текущая вероятность больше случайного числа от 0 до 99
//начинаем процесс захвата
try
{
if (sh_Owner <> ga_Races[7]) && //Если шип не принадлежит расе хааков и
(sh_Owner <> ga_Races[6]){ //и расе ксенонов,
this.SendMessageSync(28); //то произнести фразу о сдаче корабля
}
else goto L000BFDBA;
//К чему этот блок, я так и не понял, всё равно он пропущен, да и не могут эти расы кричать
//Другого варианта структуры, кроме как безусловный переход, чтобы была
// возможность не выполнить данный блок, я не нашёл, а он действительно не выполняется.
if (sh_Owner == ga_Races[7]) || //Если шип не принадлежит расе хааков и
(sh_Owner == ga_Races[6]){ //и расе ксенонов,
this.SendMessageSync(28); //то произнести фразу о сдаче корабля
}
L000BFDBA:
ga_Player.IncStatCounter(5080,1); //Увеличить число в статистике
this.GetOwner().ChangeNotorietyKill(this,AttackerEv);
//
// Здесь мог ошибиться, привожу исходный код.
//
// push SP[6] ; loc1 ; // AttackerEv
// get_object
// push 2 //число аргументов для ChangeNotorietyKill
// push 0 //число аргументов для GetOwner
// get_object
// call GetOwner ; 00000843 ; // GetOwner()
// call ChangeNotorietyKill ; //ChangeNotorietyKill(arg1,arg2)
//
this.SetRaceLogicControl(1);
this.LeaveShip(); //покидаем кораблик
} catch(...){};
} //L000BFE0C
}
}
}
}
}
}
//<L000BFE14>
//Далее процесс расчета повреждений,
//который меня не сильно интересует
//
if (arg2){
MaxLaser = AttakerEv.GetMaxLaser() + 10;
this.MakeDamage(SE_Random(MaxLaser) + 10, 0);
//Оружие наносит повреждения от 10 до 110% своей максимальной мощности
} //L000BFE50
if (AttackerOwner == ga_Player) && (AttackerEv <> ga_PlayerShip) &&
(AttackerEv <> sh_Attacker){
//Атакующий принадлежит игроку, не является кораблем, пилотируемым игроком
//и не является предыдущим атакующим
if (ga_Player.GetAge() > ga_Player.GetLastNotorietyHitTime() + 60){
//От последнего попадания прошло больше минуты
sh_Owner.AddNotoriety(ga_Player,-1);
ga_Player.SetLastNotorietyHitTime(ga_Player.GetAge());
//За каждую минуту атаки известность у определённой расы будет падать на 1 единицу
}
} //L000BFE78 -> L000BFE98 -> L000BFEF6
ShipAttacker = sh_Attacker; //loc3
LastTimeAttacked = sh_LastTime_Attacked; //loc4
AutopilotOn = 1; //loc5
if (sh_Flags & 1) {
if(arg2){
this.SetAttacker(AttackerEv);
loc5 = this.IsAutopilotActive();
} //L000BFF3E
else AutopilotOn = 0; //loc5
} //L000BFF4C
else this.AttackedByHandler(Attacker,arg2);
this.GetAttacker(); //Непонятный вызов процедуры, значение всё равно не сохраняется
//
//L000BFF60: push 0 //число аргументов для GetAttacker
// get_object //this
// call GetAttacker ; 00003A50
// pop //теряем результат вызова функции
// push SP[0] ; loc5
//
if (AutopilotOn && sh_Attacker){
if ((sh_LastTime_Attacked - LastTimeAttacked) > 1){
loc6 = 0;
if (this.IsLanding() && sh_CollisionIgnoreObj){
if (SA_FindObject(sh_CollisionIgnoreObj)){
if !(SE_IsClass(sh_Attacker,2014)){ //Attacker Is Not Gate
if (SA_GetMainType(sh_CollisionIgnoreObj) == 18) loc6 = 3; //SSTYPE_SHIP секторальный шип
else loc6 = 2;
} //L000C0022 -> L000C0056
} //L000BFFFA -> L000C0022 -> L000C0056
} //L000BFFD8 -> L000BFFFA -> L000C0022 -> L000C0056
//L000C0056:
this.Signal_Attacked(sh_Attacker,loc6)
}//L000BFFAC -> L000C006E
}//L000BFF88 -> L000C006E
if !(sh_Flags & 01h) && (sh_Owner == ga_Player) &&
!(SE_IsClass(this,2067)) { //ship is class TFIGHTDRONE
TCLIENT.NotifyAttacked(this);
}//L000C00B8
} //L000BF990 -> L000BF99E -> L000C00BC
} //L000BF952 -> L000BF99E -> L000C00BC
} //L000BF924 -> L000BF932 -> L000BF952 -> L000BF99E -> L000C00BC
} //L000BF932 -> L000BF952 -> L000BF99E -> L000C00BC
} //L000C00C0
} //L000C00C4
return 0;
}