Page 1 of 1
Error in script, please help!
PostPosted: 07 Nov 2017, 20:05
by Erdesz Balazs
Hello everyone,
I have completed my new map, and started primary testing on server with real players. Everything was going fine, until I got an error. Sadly i cannot provide replay, i accidentally overwrote it.
The error is: EAssertionFailed: "We checked that Group is not dead, hence we should have a valid Unit."
When does this issue present itself? What does this sentence mean? I cannot figure it out...
Re: Error in script, please help!
PostPosted: 07 Nov 2017, 21:18
by grayter
Please attach your script file, I'll check if there are some commands which cause the problem. Are you using r6720?
Re: Error in script, please help!
PostPosted: 07 Nov 2017, 22:07
by Erdesz Balazs
It is more than a 1.5k lines, I do not recommend you start looking into it. I own the code, and if I know what the message means I will be able to sort it out.
What I need is the meaning of this message I posted, but suit yourself if you want to read it
- Code:
{
Mod description:
- Certain Productions are increased, in order to compensate for the smaller building space
Tree Trunks: +25%
Stone: +50%
Iron: +50%
Wine: +50%
Corn: +50%
Fish: +50%
- Various Buildings appear every 15 minutes at a random location out of 3 possible ones. Destroying these buildings will grant an extra power to the destroyer.
Plague!: Each enemy player lose 1 unit every 1 sec for 2 minutes. (Total 120 units lost over the duration.)
Abundance!: Each player in team is granted 100 wine barrels and fish, 75 breads and 50 sausages. Also, every unit is put at full health. Inns become fully stocked.
God's Hand!: Enemy team loses 100% of all units of a single citizen and soldier unit type each. (75% for Militia, Bowmen, Serves, Recruits and Barbarians).
Conflagration!: Each enemy player lose 15% of their total buildings in a fire.
Weapon Fair in Town!: Each player in team is given the greater value between 20 and 40% of currently in stock for each weapon type in every Barrack.
Real Peasants' Rebellion!: [Enemy count] * 120 Rebels spawn as allies. Rebels are granted Retribution bonus and are ordered to attack closest enemy town.
}
// New Bonuses + Schoolhouse, Statistic, Caravan and Mercenary script + Towers limit
// Made by Toxic
// Extras by Erdesz Balazs
// DECLARATION:
type aPLAYER = record
Bonus: (btNone, btSurvivalists, btRich, btMasterCrafters, btToughPeople, btSnipers, btRetribution);
Buildings: record
Schools: array of Integer;
Barracks: array of Integer;
Markets: array of Integer;
Merc: array of Integer; // Special counter in Mercenary script
end;
SpecialKills: Integer; // Kills caused by bonuses (Retribution, Snipers)
Feeding: LongInt; // Survialist feed counter (it is faster 1 global feeding every cca 20 min than scan every tick if unit have hunger)
TowersCount: Byte; // Towers count for TOWERS_LIMIT
WeaponsCount: array of Integer;
end;
var
PLAYER: array of aPLAYER;
aBuildOrder: array[0..29] of array of Byte;
BonusChooseByHouses: array of Byte;
TradeRatio: array[0..27] of array [0..27] of Byte;
TradeSide: array[0..27] of array [0..27] of Boolean;
// CONSTANTS
const
TOWERS_LIMIT = 10; // Towers limit
UPDATE_OVERLAY_DELAY = 10; // Statistics upload delay
MERC_LINK_GROUPS_RAD = 20; // Radius for link groups after spawn in rally point (Mercenary script)
MERCS_SPAWN_COUNT = 10;
// Prices of 10 units from Mercenary script
REBEL_PRICE = 2;
ROGUE_PRICE = 2;
VAGABOND_PRICE = 3;
WARRIOR_PRICE = 5;
REBELS = REBEL_PRICE*MERCS_SPAWN_COUNT;
ROGUES = ROGUE_PRICE*MERCS_SPAWN_COUNT;
VAGABONDS = VAGABOND_PRICE*MERCS_SPAWN_COUNT;
WARRIORS = WARRIOR_PRICE*MERCS_SPAWN_COUNT;
type tile = record
X: integer;
Y: integer;
TileType: integer;
TileDirection: integer;
end;
type ware = record
ID: integer;
AmountAdd: integer;
TrackIncrease: integer;
Amount: Integer;
end;
var h, i, j, k, l, m, n: integer;
var t: array[0..7] of array [0..5] of ware; //tracker for ware production
var Alliance: array[0..7] of array [0..9] of boolean;
var PlayerUnits: array[0..7] of array of integer;
var PlayerInns: array[0..7] of array of integer;
var FoodTypes: array[0..3] of integer;
var ExtraStart: integer;
var ExtraDuration: integer;
var ExtraEnd: integer;
var ExtraInterval: integer;
var ExtraActive: array [0..5] of boolean;
var ExtraRecipient: Integer;
var ExtraDestriptionRemoveAfter: integer;
var NextExtra: integer;
var RandomQuestHouses: array[0..5] of integer;
var RandomQuestPlace: array[0..2] of array [0..1] of integer;
var RandomQuestLoc: integer;
var RandomQuestType: integer;
var UnitTracker: array[0..7] of array of integer;
var Extra_RandomDeath_Multiplier: integer;
var Extra_RandomDeath_Unit: integer;
var Extra_RandomSoldierTypeToKill: integer;
var PortionToKill: integer;
var Extra_RandomCitizenTypeToKill: integer;
var PortionToDestroy: integer;
var HousesToDestroy: array of integer;
var BuildingToDestroy: integer;
var UnitTypeToDie: array[0..1] of integer;
var RebelSpawnLoc: array[0..5] of array[0..1] of integer;
var RebelNumber: integer;
var RebelsToSpawn: integer;
var ExtraBuildingTiles: array[0..2] of array[0..4] of array[0..3] of tile;
var UnitsMustBeRemovedFirst: boolean;
var AlreadyRemovedUnits: boolean;
procedure Initialize;
begin
NextExtra:= States.PeaceTime + 1;
RebelsToSpawn:= 120;
for i:=0 to 7 do begin
//FILL THE WARE TRACKER
t[i][0].ID:= 0; //Tree Trunks
t[i][0].AmountAdd:= 1;
t[i][0].Amount:= 4;
t[i][0].TrackIncrease:= 5;
t[i][1].ID:= 1; //Stone
t[i][1].AmountAdd:= 1;
t[i][1].Amount:= 2;
t[i][1].TrackIncrease:= 3;
t[i][2].ID:= 6; //Iron
t[i][2].AmountAdd:= 1;
t[i][2].Amount:= 2;
t[i][2].TrackIncrease:= 3;
t[i][3].ID:= 8; //Wine Barrel
t[i][3].AmountAdd:= 1;
t[i][3].Amount:= 2;
t[i][3].TrackIncrease:= 3;
t[i][4].ID:= 9; //Corn
t[i][4].AmountAdd:= 1;
t[i][4].Amount:= 2;
t[i][4].TrackIncrease:= 3;
t[i][5].ID:= 27; //Fish
t[i][5].AmountAdd:= 1;
t[i][5].Amount:= 2;
t[i][5].TrackIncrease:= 3;
for j:=0 to 7 do begin
//CREATE ALLIANCE MATRIX
Alliance[i][j]:=States.PlayerAllianceCheck(i, j);
end;
Alliance[i][8]:= false;
Alliance[i][9]:= true;
end;
FoodTypes[0]:= 8;
FoodTypes[1]:= 10;
FoodTypes[2]:= 13;
FoodTypes[3]:= 27;
ExtraDuration:= 1200;
ExtraInterval:= 9000;
ExtraDestriptionRemoveAfter:= 600;
for i:=0 to High(ExtraActive) do begin
ExtraActive[i]:= false;
end;
RandomQuestHouses[0]:= 11; //Storehouse - Plague!
RandomQuestHouses[1]:= 27; //Inn - Abundance!
RandomQuestHouses[2]:= 21; //Barrack - God's Hand!
RandomQuestHouses[3]:= 12; //Stables - Conflagration!
RandomQuestHouses[4]:= 29; //Market Hall - Weapon Fair in Town!
RandomQuestHouses[5]:= 13; //Schholhouse - Real Peasants' Rebellion!
{RandomQuestHouses[0]:= 11; //Storehouse - Plague!
RandomQuestHouses[1]:= 27; //Inn - Abundance!
RandomQuestHouses[2]:= 21; //Barrack - God's Hand!
RandomQuestHouses[3]:= 12; //Stables - Conflagration!
RandomQuestHouses[4]:= 29; //Market Hall - Weapon Fair in Town!
RandomQuestHouses[5]:= 18; //Town Hall - Real Peasants' Rebellion!}
RandomQuestPlace[0][0]:= 55; //pos0_X
RandomQuestPlace[0][1]:= 126; //pos0_Y
RandomQuestPlace[1][0]:= 123; //pos1_X
RandomQuestPlace[1][1]:= 126; //pos1_Y
RandomQuestPlace[2][0]:= 192; //pos2_X
RandomQuestPlace[2][1]:= 126; //pos2_Y
RebelSpawnLoc[0][0]:= 38;
RebelSpawnLoc[0][1]:= 126;
RebelSpawnLoc[1][0]:= 72;
RebelSpawnLoc[1][1]:= 126;
RebelSpawnLoc[2][0]:= 105;
RebelSpawnLoc[2][1]:= 126;
RebelSpawnLoc[3][0]:= 141;
RebelSpawnLoc[3][1]:= 126;
RebelSpawnLoc[4][0]:= 174;
RebelSpawnLoc[4][1]:= 126;
RebelSpawnLoc[5][0]:= 208;
RebelSpawnLoc[5][1]:= 126;
for h:=0 to High(RandomQuestPlace) do begin
for i:= 0 to High(ExtraBuildingTiles[h]) do begin
for j:= 0 to High(ExtraBuildingTiles[h][i]) do begin
ExtraBuildingTiles[h][i][j].X:= RandomQuestPlace[h][0] + (i - 2);
ExtraBuildingTiles[h][i][j].Y:= RandomQuestPlace[h][1] + (j - 3);
ExtraBuildingTiles[h][i][j].TileType:= States.MapTileType(ExtraBuildingTiles[h][i][j].X, ExtraBuildingTiles[h][i][j].Y);
ExtraBuildingTiles[h][i][j].TileDirection:= States.MapTileRotation(ExtraBuildingTiles[h][i][j].X, ExtraBuildingTiles[h][i][j].Y);
end;
end;
end;
UnitsMustBeRemovedFirst:= false;
PortionToKill:= 75 //x% will die if it's spammable unit type (Militia, Barbarian, Bowmen, XBowmen, Serf, Recruit)
PortionToDestroy:= 15 //x% of all buildings are destroyed.
end;
function Abs(const A: Integer): Integer; begin if A < 0 then RESULT := -A else RESULT := A; end;
// HOUSES management
procedure AddHouse(const ID: Integer; out Houses: array of Integer);
begin
SetLength(Houses, Length(Houses)+1);
Houses[High(Houses)] := ID;
end;
procedure RemoveHouse(const ID: Integer; out Houses: array of Integer);
var i: Integer;
begin
for i := 0 to High(Houses) do
if (Houses[i] = ID) or (States.HouseOwner(Houses[i]) > 7) then break;
Houses[i] := Houses[High(Houses)];
SetLength(Houses, High(Houses));
end;
procedure RemoveMarket(const ID: Integer; out Market, Merc: array of Integer);
var i: Integer;
begin
for i := 0 to High(Market) do
if (Market[i] = ID) then break;
Market[i] := Market[High(Market)];
Merc[i] := Merc[High(Merc)];
SetLength(Market, High(Market));
SetLength(Merc, High(Merc));
end;
// SCHOOLHOUSE script
procedure Recruits(const PL: Integer);
var i: Integer;
begin
for i := 0 to High(PLAYER[PL].Buildings.Schools) do
if States.HouseRepair(PLAYER[PL].Buildings.Schools[i]) AND (States.HouseResourceAmount(PLAYER[PL].Buildings.Schools[i], 7) > 0) AND (States.HouseSchoolQueue(PLAYER[PL].Buildings.Schools[i], 0) = - 1) then
Actions.HouseSchoolQueueAdd(PLAYER[PL].Buildings.Schools[i], 13, 1);
end;
// MERCENARY units
procedure Mercenary(const PL, ID, addGold, mercCost, mercType, groupType: Integer);
var i, X, Y, IDNew, IDClosest: Integer;
begin
for i := 0 to High(PLAYER[PL].Buildings.Merc) do
if ID = PLAYER[PL].Buildings.Markets[i] then break;
PLAYER[PL].Buildings.Merc[i] := PLAYER[PL].Buildings.Merc[i] + addGold;
if PLAYER[PL].Buildings.Merc[i] >= mercCost then begin
PLAYER[PL].Buildings.Merc[i] := PLAYER[PL].Buildings.Merc[i] - mercCost;
if length(PLAYER[PL].Buildings.Barracks) <> 0 then begin
X := States.HouseBarracksRallyPointX(PLAYER[PL].Buildings.Barracks[0]);
Y := States.HouseBarracksRallyPointY(PLAYER[PL].Buildings.Barracks[0]);
end else begin
X := States.HousePositionX(ID);
Y := States.HousePositionY(ID);
end;
IDClosest := States.ClosestGroup(PL, X, Y, groupType);
IDNew := Actions.GiveGroup(PL, mercType, States.HousePositionX(ID), States.HousePositionY(ID), 0, MERCS_SPAWN_COUNT, 5);
if (IDClosest > 0) AND ( (Abs(X-States.UnitPositionX(States.GroupMember(IDClosest,0)))+Abs(Y-States.UnitPositionY(States.GroupMember(IDClosest,0)))) < MERC_LINK_GROUPS_RAD ) then
Actions.GroupOrderLink(IDNew, IDClosest)
else
Actions.GroupOrderWalk(IDNew,X,Y,0);
end;
end;
// CARAVAN script
procedure TradeCalculation();// Rich player trades cca 10 000x per a game so we calculate ratio once and save this value
var i,j: Byte;
ratio: Double;
begin
for i := 0 to 27 do begin
for j := 0 to 27 do begin
ratio := States.MarketValue(i) / (States.MarketValue(j)*States.MarketLossFactor());
if ratio < 1 then begin
TradeRatio[i][j] := Round(1/ratio);
TradeSide[i][j] := True;
end else begin
TradeRatio[i][j] := Round(ratio);
TradeSide[i][j] := False;
end;
end;
end;
end;
procedure GiveWares(const PL, Ware, Count: Integer);
begin
Actions.GiveWares(PL,Ware,Count);
if (PLAYER[PL].Bonus = btMasterCrafters) AND (Ware >=16) AND (Ware <= 26) then // Master crafters fix
PLAYER[PL].WeaponsCount[Ware-16] := PLAYER[PL].WeaponsCount[Ware-16] + Count;
end;
procedure TakeWares(const PL, ID, Ware, Count: Integer);
begin
Actions.HouseTakeWaresFrom(ID,Ware,Count);
if (PLAYER[PL].Bonus = btMasterCrafters) AND (Ware >=16) AND (Ware <= 26) then // Master crafters fix
PLAYER[PL].WeaponsCount[Ware-16] := PLAYER[PL].WeaponsCount[Ware-16] - Count;
end;
procedure Caravan(const ID, aFrom, aTo: Integer);
var recipient, PL: Integer;
begin
PL := States.HouseOwner(ID);
if (PLAYER[PL].Bonus = btMasterCrafters) AND (aTo >=16) AND (aTo <= 26) then
Inc(PLAYER[PL].WeaponsCount[aTo-16]);
if aFrom < aTo then recipient := aTo-1
else recipient := aTo;
if (recipient < 8) AND (PL <> recipient) AND (States.PlayerAllianceCheck(PL, recipient)) then begin
if TradeSide[aFrom][aTo] then begin
GiveWares(recipient, aFrom, TradeRatio[aFrom][aTo]);
TakeWares(PL, ID, aFrom, 1);
end else begin
GiveWares(recipient, aFrom, 1);
TakeWares(PL, ID, aFrom, TradeRatio[aFrom][aTo]);
end;
end
// Mercenary hire
else if (aTo = 22) AND (aFrom = 7) then begin
Mercenary(PL, ID, 4, REBELS, 24, 1); // Lance -> Rebel
TakeWares(PL, ID, aTo, 1);
end else if (aTo = 24) AND (aFrom = 7) then begin
Mercenary(PL, ID, 4, ROGUES, 25, 2); // Longbow -> Rogue
TakeWares(PL, ID, aTo, 1);
end else if (aTo = 26) AND (aFrom = 7) then begin
Mercenary(PL, ID, 8, VAGABONDS, 27, 3); // Horse -> Vagabond
TakeWares(PL, ID, aTo, 1);
end else if (aTo = 20) AND (aFrom = 7) then begin
Mercenary(PL, ID, 4, WARRIORS, 26, 0); // Handaxe -> Warrior
TakeWares(PL, ID, aTo, 1);
end else begin
//Actions.HouseRepairEnable(ID,False);
Actions.MarketSetTrade(ID, aFrom, aTo, 0);
Actions.PlayWAV(PL, 'wCant', 1);
end;
end;
// Weapons from destroyed barracks
procedure GiveBarracksWeapons(const aHouse, PL: Integer);
var i: Integer;
begin
for i := 16 to 26 do begin
Actions.GiveWeapons(PL,i,States.HouseResourceAmount(aHouse,i));
if PLAYER[PL].Bonus = btMasterCrafters then
PLAYER[PL].WeaponsCount[i-16] := PLAYER[PL].WeaponsCount[i-16] + States.HouseResourceAmount(aHouse,i);
end;
end;
// BONUSES script
procedure GiveWeapons(const weapons: Array of Byte; const PL: Integer);
var i: Integer;
begin
if (States.StatHouseTypeCount(PL, 21) > 0) then
for i := 0 to High(weapons) do Actions.GiveWeapons(PL, weapons[i], 1);
end;
procedure GiveReward(const ware, PL, Count: Integer);
begin
if (States.StatHouseTypeCount(PL, 11) > 0) then Actions.GiveWares(PL, ware, Count);
end;
// Survivalists
procedure Survivalist(const PL: Integer);
var aiUnits: array of Integer;
var i: Integer;
begin
if States.GameTime div PLAYER[PL].Feeding > 1 then begin
PLAYER[PL].Feeding := PLAYER[PL].Feeding + 5000; // feeding each cca 17 min
aiUnits := States.PlayerGetAllUnits(PL);
for i := 0 to High(aiUnits) do
Actions.UnitHungerSet(aiUnits[i], States.UnitMaxHunger);
end;
end;
// Rich - schoolhouse gold
procedure GiveGold(const PL: Integer);
var i: Integer;
begin
for i := 0 to High(PLAYER[PL].Buildings.Schools) do
if States.HouseResourceAmount(PLAYER[PL].Buildings.Schools[i], 7) < 5 then Actions.HouseAddWaresTo(PLAYER[PL].Buildings.Schools[i], 7, 1);
end;
procedure CloseSchool(const ID: Integer);
begin
Actions.HouseDeliveryBlock(ID, True);
if States.HouseResourceAmount(ID, 7) < 5 then
Actions.HouseAddWaresTo(ID, 7, 5-States.HouseResourceAmount(ID, 7));
end;
// Rich - trade
procedure DoubleTrade(const aMarket, aFromWare, aToWare: Integer);
begin
if TradeSide[aFromWare][aToWare] then Actions.HouseAddWaresTo(aMarket, aToWare,1)
else Actions.HouseAddWaresTo(aMarket, aToWare, TradeRatio[aFromWare][aToWare]);
end;
// Master crafters - add weapons to Barracks and faster building
procedure MasterCrafter(const PL: Integer);
var i, j: Integer;
aiHouses: array of Integer;
begin
if (Length(PLAYER[PL].Buildings.Barracks) > 0) then
for i := 0 to High(PLAYER[PL].WeaponsCount) do
if (PLAYER[PL].WeaponsCount[i] - States.StatResourceProducedCount(PL, i+16)) <= 0 then begin
PLAYER[PL].WeaponsCount[i] := PLAYER[PL].WeaponsCount[i] + 3;
Actions.GiveWeapons(PL,i+16,1);
end;
aiHouses := States.PlayerGetAllHouses(PL);
for i := 0 to High(aiHouses) do
if not States.HouseIsComplete(aiHouses[i]) then
if (States.HouseBuildingProgress(aiHouses[i]) mod 50 > 0) AND (States.HouseBuildingProgress(aiHouses[i]) mod 50 <= 50) then
for j := 0 to 10 do Actions.HouseAddBuildingProgress(aiHouses[i]);
end;
// Tough People - switch militia -> barbarian
procedure SwitchToBarbarian(const UnitID, GroupID: Integer);
var aBarracks: Integer;
begin
if States.UnitType(UnitID) = 14 then begin
aBarracks := States.ClosestHouse(States.UnitOwner(UnitID), States.UnitPositionX(UnitID), States.UnitPositionY(UnitID), 21);
if aBarracks > -1 then begin
if States.PlayerIsAI(States.UnitOwner(UnitID)) = True then Actions.HouseAddWaresTo(aBarracks, 20, 1); // Help to AI
if (States.HouseResourceAmount(aBarracks, 20) >= 1) then begin
Actions.HouseTakeWaresFrom(aBarracks, 20, 1);
Actions.GroupOrderLink(Actions.GiveGroup(States.UnitOwner(UnitID), 23, States.UnitPositionX(UnitID), States.UnitPositionY(UnitID), States.UnitDirection(UnitID),1,1), GroupID);
end else begin
Actions.HouseBarracksGiveRecruit(aBarracks);
Actions.HouseAddWaresTo(aBarracks, 20, 1);
end;
Actions.UnitKill(UnitID, True);
end;
end;
end;
// Tough People - rewards
procedure Reward(const UnitID, KillerOwner: Integer);
begin
case States.UnitType(UnitID) of
15: GiveWeapons([16,18],KillerOwner); //Axe Fighter
16: GiveWeapons([17,19,21],KillerOwner); //Sword Fighter
17: GiveWeapons([18,24],KillerOwner); //Bowman
18: GiveWeapons([19,25],KillerOwner); //Crossbowman
19: GiveWeapons([18,22],KillerOwner); //Lance carrier
20: GiveWeapons([19,23],KillerOwner); //Pikeman
21: GiveWeapons([16,18,26],KillerOwner); //Scout
22: GiveWeapons([17,19,21,26],KillerOwner); //Knight
end;
end;
// Snipers - kill defender if attacker is long range unit
procedure Sniper(const UnitID, AttackerID: Integer);
begin
if (States.UnitType(AttackerID) = 17 ) OR (States.UnitType(AttackerID) = 18 ) then if States.KamRandom() < 0.04 then begin
if (States.UnitType(UnitID) > 13) AND (States.UnitType(UnitID) < 28) then PLAYER[States.UnitOwner(AttackerID)].SpecialKills := PLAYER[States.UnitOwner(AttackerID)].SpecialKills + 1;
Actions.UnitKill(UnitID, False);
end;
end;
// Retribution - kill attacker
procedure Retribute(const UnitID, AttackerID: Integer);
begin
if (States.KamRandom() < 0.04) and (States.UnitType(UnitID) > 13) and (States.UnitType(UnitID) < 28) then begin
PLAYER[States.UnitOwner(UnitID)].SpecialKills := PLAYER[States.UnitOwner(UnitID)].SpecialKills + 1;
Actions.UnitKill(AttackerID, False);
end;
end;
// Building order procedures:
procedure CheckBuildOrder(const aHouse: Integer);
var i: Integer;
begin
if Length(aBuildOrder[States.HouseType(aHouse)]) > 0 then
for i := 0 to High(aBuildOrder[States.HouseType(aHouse)]) do
if not (States.HouseUnlocked(States.HouseOwner(aHouse), aBuildOrder[States.HouseType(aHouse)][i])) then begin
Actions.HouseAllow(States.HouseOwner(aHouse), aBuildOrder[States.HouseType(aHouse)][i], True);
Actions.HouseUnlock(States.HouseOwner(aHouse), aBuildOrder[States.HouseType(aHouse)][i]);
end;
end;
procedure unlockAllBuildings(const PL: Integer);
var i: Integer;
var aiHouses: array of Integer;
begin
aiHouses := States.PlayerGetAllHouses(PL);
for i := 0 to 29 do if (i <> 26) and (i <> 27) then begin
Actions.HouseUnlock(PL, i);
Actions.HouseAllow(PL, i, True);
end;
if (PLAYER[PL].Bonus <> btSurvivalists) then begin Actions.HouseAllow(PL, 27, True); Actions.HouseUnlock(PL, 27); end;
end;
procedure SetBuildOrder(const PL: Integer);
var i: Integer;
var aiHouses: array of Integer;
begin
for i := 0 to 29 do if (i <> 26) then Actions.HouseAllow(PL, i, False);
if (PLAYER[PL].Bonus = btSurvivalists) or (PLAYER[PL].Bonus = btMasterCrafters) then
unlockAllBuildings(PL)
else begin
aiHouses := States.PlayerGetAllHouses(PL);
for i := 0 to High(aiHouses) do CheckBuildOrder(aiHouses[i]);
end;
end;
//Choose a bonus
procedure ChoseMasterCrafters(const PL: Integer);
var i: Integer;
begin
PLAYER[PL].Bonus := btMasterCrafters;
Actions.ShowMSG(PL, '<$1>');
SetLength(PLAYER[PL].WeaponsCount, 11);
for i := 0 to High(PLAYER[PL].WeaponsCount) do PLAYER[PL].WeaponsCount[i] := 1;
end;
procedure ChoseRich(const PL: Integer);
var i: Integer;
aiHouses: array of Integer;
begin
PLAYER[PL].Bonus := btRich;
Actions.ShowMSG(PL, '<$3>');
for i := 0 to High(PLAYER[PL].Buildings.Schools) do
CloseSchool(PLAYER[PL].Buildings.Schools[i]);
aiHouses := States.PlayerGetAllHouses(PL);
end;
procedure ChoseSurvivalists(const PL: Integer); begin PLAYER[PL].Bonus := btSurvivalists; Actions.ShowMSG(PL, '<$7>'); PLAYER[PL].Feeding := 1; end;
procedure ChoseToughPeople(const PL: Integer); begin PLAYER[PL].Bonus := btToughPeople; Actions.ShowMSG(PL, '<$2>'); end;
procedure ChoseSnipers(const PL: Integer); begin PLAYER[PL].Bonus := btSnipers; Actions.ShowMSG(PL, '<$4>'); PLAYER[PL].SpecialKills := 0; end;
procedure ChoseRetribution(const PL: Integer); begin PLAYER[PL].Bonus := btRetribution; Actions.ShowMSG(PL, '<$5>'); PLAYER[PL].SpecialKills := 0; end;
procedure ChooseBonus(const PL, aType, aX, aY: Integer);
begin
case aType of
BonusChooseByHouses[0]: ChoseSurvivalists(PL);
BonusChooseByHouses[1]: ChoseRich(PL);
BonusChooseByHouses[2]: ChoseMasterCrafters(PL);
BonusChooseByHouses[3]: ChoseToughPeople(PL);
BonusChooseByHouses[4]: ChoseSnipers(PL);
BonusChooseByHouses[5]: ChoseRetribution(PL);
end;
SetBuildOrder(PL);
Actions.PlanRemove(PL, aX, aY);
end;
function CountEnemiesToPlayer(Player: integer) : integer;
begin
j:=0;
For i:=0 to 7 do begin
if (Alliance[Player][i] = false) and (States.PlayerEnabled(i) = true) then inc(j);
end;
Result:= j;
end;
//Update Overlay
procedure UpdateOverlay();
var i, j, PL, recipient, aFrom, aTo, count, value: Integer;
str: String;
begin
Actions.OverlayTextSet(-1, '');
// PLAYERS
for PL := 0 to 7 do
if States.PlayerEnabled(PL) then begin
// BONUSES
case PLAYER[PL].Bonus of
btSurvivalists: str := '<$8>';
btRich: str := '<$9>';
btMasterCrafters: str := '<$10>';
btToughPeople: str := '<$11>';
btSnipers: str := '<$12>'+IntToStr(PLAYER[PL].SpecialKills)+'[].';
btRetribution: str := '<$13>'+IntToStr(PLAYER[PL].SpecialKills)+'[].';
else str := '';
end;
// STATISTICS
value := 0;
for i := 14 to 26 do value := value + States.StatUnitKilledCount(PL,i);
for j := 0 to 7 do
if States.PlayerEnabled(j) then begin
if ((PL = j) OR States.PlayerAllianceCheck(PL, j)) and (PL < 9) then begin
// BONUSES & STATISTICS
Actions.OverlayTextAppendFormatted(j, '<$14>'+str+'<$15>', [States.PlayerColorText(PL), States.PlayerName(PL), value, States.StatArmyCount(PL)]);
end;
end;
if (States.GameTime - ExtraStart < 600) And (ExtraStart > 2) then begin
case RandomQuestType of
0: Actions.OverlayTextAppendFormatted(PL, '|<$27>|', [States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient)]);
1: Actions.OverlayTextAppendFormatted(PL, '|<$28>|', [States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient)]);
2: Actions.OverlayTextAppendFormatted(PL, '|<$29>|', [States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient), States.UnitTypeName(UnitTypeToDie[0]), States.UnitTypeName(UnitTypeToDie[1])]);
3: Actions.OverlayTextAppendFormatted(PL, '|<$30>|', [States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient), PortionToDestroy]);
4: Actions.OverlayTextAppendFormatted(PL, '|<$31>|', [States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient)]);
5: Actions.OverlayTextAppendFormatted(PL, '|<$32>|', [RebelNumber, States.PlayerColorText(ExtraRecipient), States.PlayerName(ExtraRecipient)]);
end;
end;
if NextExtra - States.GameTime > 0 then begin
Actions.OverlayTextAppendFormatted(PL, '|<$26>|', [((NextExtra - States.GameTime) div 600), (((NextExtra - States.GameTime) mod 600) div 100), (((NextExtra - States.GameTime) mod 600) mod 100) div 10]);
end;
// MARKETS
value := 0;
for i := 0 to High(PLAYER[PL].Buildings.Markets) do if States.HouseRepair(PLAYER[PL].Buildings.Markets[i]) then begin
count := States.MarketOrderAmount(PLAYER[PL].Buildings.Markets[i]);
if count > 0 then begin
aFrom := States.MarketFromWare(PLAYER[PL].Buildings.Markets[i]);
aTo := States.MarketToWare(PLAYER[PL].Buildings.Markets[i]);
// MERCENARY - check peace time
if (aFrom = 7) AND ( (aTo = 20) OR (aTo = 22) OR (aTo = 24) OR (aTo = 26) ) then begin
if States.GameTime < States.PeaceTime then begin
Actions.MarketSetTrade(PLAYER[PL].Buildings.Markets[i], aFrom, aTo, 0);
Actions.ShowMsg(PL, '<$18>');
Actions.PlayWAV(PL, 'wCant', 1);
end;
end
// CARAVAN
else begin
if TradeSide[aFrom][aTo] then count := count*TradeRatio[aFrom][aTo];
if aFrom < aTo then recipient := aTo-1
else recipient := aTo;
value := value+1;
if (recipient < 8) AND (States.PlayerEnabled(recipient)) AND (States.PlayerAllianceCheck(PL, recipient)) then begin
for j := 0 to 7 do if States.PlayerEnabled(j) AND States.PlayerAllianceCheck(j, PL) then begin//AND States.PlayerAllianceCheck(j, recipient)
if (value = 1) then Actions.OverlayTextAppend(j,'|');
Actions.OverlayTextAppendFormatted(j, '<$16>', [count,States.WareTypeName(aFrom),States.PlayerColorText(recipient),States.PlayerName(recipient)])
end;
end else begin
Actions.MarketSetTrade(PLAYER[PL].Buildings.Markets[i], aFrom, aTo, 0);
Actions.PlayWAV(PL, 'wCant', 1);
end;
end;
end;
end;
end;
end;
procedure MultiplyWares(WareType, player: integer);
begin
if (t[player][WareType].Amount - States.StatResourceProducedCount(player,t[player][WareType].ID)) <= 0 then begin
t[player][WareType].Amount := t[player][WareType].Amount + t[player][WareType].TrackIncrease;
Actions.GiveWares(player, t[player][WareType].ID, t[player][WareType].AmountAdd);
MultiplyWares(WareType, player);
end;
end;
function Max(integy, intketto: integer) : integer;
begin
if integy > intketto then Result:= integy else Result:= intketto;
end;
procedure GiveWeaponFair(Barrack: integer);
begin
For i:=16 to 26 do begin
Actions.HouseAddWaresTo(Barrack, i, Max(20, States.HouseResourceAmount(Barrack, i) * 40 div 100));
end;
end;
procedure AddInn(out Inns: array of Integer; const Inn: Integer);
begin
SetLength(Inns, Length(Inns) + 1);
Inns[High(Inns)]:= Inn;
end;
procedure RemoveInn(out Inns: array of Integer; const Inn: Integer);
begin
m:= 0;
while (Inns[m] <> Inn) do begin
Inc(m);
end;
for n:= (m + 1) to High(Inns) do begin
Inns[n-1]:= Inns[n];
end;
SetLength(Inns, Length(Inns) - 1)
end;
procedure FillEveryInn(const Inns: array of Integer);
begin
for m:=0 to High(Inns) do begin
t[States.HouseOwner(Inns[m])][3].Amount:= t[States.HouseOwner(Inns[m])][3].Amount + 5 - States.HouseResourceAmount(Inns[m], 0);
t[States.HouseOwner(Inns[m])][5].Amount:= t[States.HouseOwner(Inns[m])][5].Amount + 5 - States.HouseResourceAmount(Inns[m], 27);
for n:=0 to High(FoodTypes) do begin
Actions.HouseAddWaresTo(Inns[m], FoodTypes[n], 5 - States.HouseResourceAmount(Inns[m], n));
end;
end;
end;
procedure FeedEveryUnit(Units: array of integer);
begin
for n:=0 to High(Units) do begin
Actions.UnitHungerSet(Units[n], States.UnitMaxHunger);
end;
end;
procedure AddExtraFoodToStore(Player: Integer);
begin
Actions.GiveWares(Player, FoodTypes[0], 100);
Actions.GiveWares(Player, FoodTypes[1], 75);
Actions.GiveWares(Player, FoodTypes[2], 50);
Actions.GiveWares(Player, FoodTypes[3], 100);
t[Player][3].Amount:= t[Player][3].Amount + 100;
t[Player][5].Amount:= t[Player][5].Amount + 100;
end;
procedure Extra_RandomDeath(Beneficiary, Attacked: Integer);
begin
//IF PLAYER IS ENEMY, IT WILL LOSE A RANDOM UNIT THIS TICK
if Alliance[Beneficiary][Attacked] = false and
(States.PlayerEnabled(Attacked) = true) and
(States.PlayerDefeated(Attacked) = false) then begin
UnitTracker[Attacked]:= States.PlayerGetAllUnits(Attacked);
if High(UnitTracker[Attacked]) = -1 then exit;
Extra_RandomDeath_Unit:= States.KamRandomI(High(UnitTracker[Attacked])+1);
Actions.UnitKill(UnitTracker[Attacked][Extra_RandomDeath_Unit], false);
end;
end;
procedure KillRandomType(UnitType, Player: integer);
var Units: array of integer;
var NumberOfUnitTypeUnits, UnitsAlreadyKilled: integer;
begin
Units:= States.PlayerGetAllUnits(Player);
NumberOfUnitTypeUnits:= 0;
UnitsAlreadyKilled:= 0;
For m:=0 to High(Units) do begin
if States.UnitType(Units[m]) = UnitType then inc(NumberOfUnitTypeUnits);
end;
For m:=0 to High(Units) do begin
case UnitType of
0, 13, 14, 17, 18, 23: begin
if (States.UnitType(Units[m]) = UnitType) and
(UnitsAlreadyKilled < ((NumberOfUnitTypeUnits * PortionToKill) div 100)) then begin
Actions.UnitKill(Units[m], false);
inc(UnitsAlreadyKilled);
end;
end;
else begin
if (States.UnitType(Units[m]) = UnitType) then begin
Actions.UnitKill(Units[m], false);
inc(UnitsAlreadyKilled);
end;
end;
end;
end;
end;
procedure RemoveCheaterField(aPlayer, aX, aY: integer);
begin
for i:=0 to High(RandomQuestPlace) do begin
case i of
0, 2: begin
if (Abs(aX - RandomQuestPlace[i][0]) <= 20) And (Abs(aY - RandomQuestPlace[i][1]) <= 20) then begin
Actions.PlanRemove(aPlayer, aX, aY);
if States.PlayerIsAI(aPlayer) then Actions.AIAutoBuild(aPlayer, false);
end;
end;
1: begin
if (((aX - RandomQuestPlace[i][0]) >= -27) And ((aX - RandomQuestPlace[i][0]) <= 25)) And
(((aY - RandomQuestPlace[i][1] >= -13) And ((aY - RandomQuestPlace[i][1]) <= 12))) then begin
Actions.PlanRemove(aPlayer, aX, aY);
if States.PlayerIsAI(aPlayer) then Actions.AIAutoBuild(aPlayer, false);
end;
end;
end;
end;
end;
// EVENTS
procedure OnPlanFieldPlaced(aPlayer, aX, aY: Integer);
begin
RemoveCheaterField(aPlayer, aX, aY);
end;
procedure OnPlanRoadPlaced(aPlayer, aX, aY: Integer);
begin
RemoveCheaterField(aPlayer, aX, aY);
end;
procedure OnPlanWinefieldPlaced(aPlayer, aX, aY: Integer);
begin
RemoveCheaterField(aPlayer, aX, aY);
end;
procedure OnHousePlanPlaced(PL, aX, aY, THouseType: Integer);
begin
if PLAYER[PL].Bonus = btNone then ChooseBonus(PL, THouseType, aX, aY)
// if ((States.StatHouseTypeCount(PL, 17)+States.StatHouseTypePlansCount(PL, 17)) > TOWERS_LIMIT) then
// - THIS DOES NOT WORK!!! StatHouseTypeCount takes ONLY COMPLETED HOUSES and StatHouseTypePlansCount takes ONLY UNTOUCHED PLANS so there still are plans with uncompleted houses
else if THouseType = 17 then
if PLAYER[PL].TowersCount < TOWERS_LIMIT then
Inc(PLAYER[PL].TowersCount)
else begin
Actions.ShowMSG(PL, '<$17> '+IntToStr(TOWERS_LIMIT)+'!');
Actions.PlanRemove(PL, aX, aY);
end;
RemoveCheaterField(PL, aX, aY);
end;
procedure OnHousePlanRemoved(PL: Integer; aX: Integer; aY: Integer; THouseType: Integer);
begin
if THouseType = 17 then Dec(PLAYER[PL].TowersCount);
end;
procedure OnHouseBuilt(aHouse: Integer);
begin
if not States.PlayerIsAI(States.HouseOwner(aHouse)) and not (PLAYER[States.HouseOwner(aHouse)].Bonus = btSurvivalists) and not (PLAYER[States.HouseOwner(aHouse)].Bonus = btMasterCrafters) then CheckBuildOrder(aHouse);
if (States.HouseType(aHouse) = 13) then begin
AddHouse(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Schools);
CloseSchool(aHouse);
end else if (States.HouseType(aHouse) = 21) then AddHouse(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Barracks)
else if (States.HouseType(aHouse) = 29) then begin
AddHouse(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Markets);
AddHouse(0, PLAYER[States.HouseOwner(aHouse)].Buildings.Merc);
end;
if (States.HouseType(aHouse) = 27) and (States.HouseOwner(aHouse) < 8) then begin
AddInn(PlayerInns[States.HouseOwner(aHouse)], aHouse);
end;
end;
procedure OnHouseDestroyed(aHouse, aDestroyerIndex: Integer);
begin
if States.HouseIsComplete(aHouse) and (States.HouseOwner(aHouse) < 8) then begin
if (States.HouseType(aHouse) = 13) then RemoveHouse(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Schools)
else if (States.HouseType(aHouse) = 21) then begin
RemoveHouse(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Barracks);
if States.HouseOwner(aHouse) <> aDestroyerIndex then GiveBarracksWeapons(aHouse, aDestroyerIndex);
end else if (States.HouseType(aHouse) = 29) then RemoveMarket(aHouse, PLAYER[States.HouseOwner(aHouse)].Buildings.Markets, PLAYER[States.HouseOwner(aHouse)].Buildings.Merc);
end;
if (States.HouseType(aHouse) = 17) then Dec(PLAYER[States.HouseOwner(aHouse)].TowersCount);
if (States.HouseOwner(aHouse) = 8) then begin
ExtraRecipient:= aDestroyerIndex;
ExtraStart:= States.GameTime;
ExtraEnd:= ExtraStart + ExtraDuration;
RebelNumber:= CountEnemiesToPlayer(ExtraRecipient) * RebelsToSpawn;
for m:= 0 to High(RandomQuestHouses) do begin
if States.HouseType(aHouse) = RandomQuestHouses[m] then begin
ExtraActive[m]:= true;
AlreadyRemovedUnits:=false;
end;
end;
end;
if (States.HouseType(aHouse) = 27) and (States.HouseOwner(aHouse) < 8) then begin
if States.HouseIsComplete(aHouse) then RemoveInn(PlayerInns[States.HouseOwner(aHouse)], aHouse);
end;
end;
procedure OnMarketTrade(aMarket, aFrom, TWareType: Integer);
begin
if States.HouseRepair(aMarket) then Caravan(aMarket, aFrom, TWareType)
else if PLAYER[States.HouseOwner(aMarket)].Bonus = btRich then DoubleTrade(aMarket, aFrom, TWareType);
end;
procedure OnUnitTrained(UnitID: Integer);
var PL: Integer;
begin
PL := States.UnitOwner(UnitID);
if (PL <> -1) then GiveGold(PL);
end;
procedure OnWarriorEquipped(UnitID, aGroupID: Integer);
begin
if PLAYER[States.UnitOwner(UnitID)].Bonus = btToughPeople then SwitchToBarbarian(UnitID, aGroupID);
end;
procedure OnUnitAttacked(UnitID, AttackerID: Integer);
begin
if (AttackerID > -1) AND (UnitID > -1) then
if (not States.UnitDead(AttackerID)) AND (not States.UnitDead(UnitID)) then begin
if States.UnitOwner(AttackerID) > -1 then if PLAYER[States.UnitOwner(AttackerID)].Bonus = btSnipers then Sniper(UnitID, AttackerID);
if States.UnitOwner(UnitID) > -1 then if PLAYER[States.UnitOwner(UnitID)].Bonus = btRetribution then Retribute(UnitID, AttackerID);
end;
end;
{
procedure OnUnitWounded(aUnit, aAttacker: Integer);
begin
end;
}
procedure OnUnitDied(UnitID, aKillerOwner: Integer);
begin
if (aKillerOwner > -1) AND (aKillerOwner < 8) AND (PLAYER[aKillerOwner].Bonus = btToughPeople) AND (States.KaMRandom()<0.3) then Reward(UnitID, aKillerOwner);
end;
procedure OnMissionStart;
var PL, i: Integer;
aiHouses: array of Integer;
text: String;
begin
Initialize();
Actions.ShowMSG(-1, '<$25>');
aBuildOrder[0] := [3, 4, 5, 6, 8, 19, 21, 28, 29];aBuildOrder[1] := [2, 10, 23];aBuildOrder[2] := [];aBuildOrder[3] := [];aBuildOrder[4] := [1];aBuildOrder[5] := [15];aBuildOrder[6] := [];aBuildOrder[7] := [];aBuildOrder[8] := [12, 16, 22];aBuildOrder[9] := [0];aBuildOrder[10] := [];aBuildOrder[11] := [11, 13];aBuildOrder[12] := [];aBuildOrder[13] := [14, 27];aBuildOrder[14] := [9, 17];aBuildOrder[15] := [18];aBuildOrder[16] := [24, 25];aBuildOrder[17] := [];aBuildOrder[18] := [];aBuildOrder[19] := [];aBuildOrder[20] := [];aBuildOrder[21] := [];aBuildOrder[22] := [7];aBuildOrder[23] := [];aBuildOrder[24] := [];aBuildOrder[25] := [20];aBuildOrder[26] := [];aBuildOrder[27] := [14];aBuildOrder[28] := [];aBuildOrder[29] := [];
BonusChooseByHouses := [27, 15, 1, 21, 17, 29]; //[Inn, Metallurgist's, Iron Smithy, Barracks, Watchtower, Market]
TradeCalculation();
SetLength(PLAYER, 10);
for PL := 0 to 7 do if States.PlayerEnabled(PL) then begin
// Schoolhouse + Castle + Towers count
aiHouses := States.PlayerGetAllHouses(PL);
PLAYER[PL].TowersCount := 0;
for i := 0 to High(aiHouses) do begin
if (States.HouseType(aiHouses[i]) = 13) and States.HouseIsComplete(aiHouses[i]) then AddHouse(aiHouses[i], PLAYER[PL].Buildings.Schools)
else if (States.HouseType(aiHouses[i]) = 21) and States.HouseIsComplete(aiHouses[i]) then AddHouse(aiHouses[i], PLAYER[PL].Buildings.Barracks)
else if (States.HouseType(aiHouses[i]) = 29) and States.HouseIsComplete(aiHouses[i]) then begin
AddHouse(aiHouses[i], PLAYER[PL].Buildings.Markets);
AddHouse(0, PLAYER[PL].Buildings.Merc);
end else if (States.HouseType(aiHouses[i]) = 17) then PLAYER[PL].TowersCount := PLAYER[PL].TowersCount + 1;
end;
// Building order (Bonuses)
for i := 0 to 29 do if (i <> 26) then Actions.HouseAllow(PL, i, False);
for i := Low(BonusChooseByHouses) to High(BonusChooseByHouses) do begin
Actions.HouseAllow(PL, BonusChooseByHouses[i], True);
Actions.HouseUnlock(PL, BonusChooseByHouses[i]);
end;
// AI Bonus
if States.PlayerIsAI(PL) then begin
case States.KamRandomI(4) of
0: ChoseRetribution(PL);
1: ChoseSnipers(PL);
2: ChoseMasterCrafters(PL);
3: ChoseToughPeople(PL);
end;
// AI configuration
unlockAllBuildings(PL); // AI works only with specific unlock order (or with everything on)
Actions.AIEquipRate(PL,0,0);
Actions.AIEquipRate(PL,1,0);
Actions.AIWorkerLimit(PL, 35);
//Actions.AISerfsPerHouse(PL, 1.5);// KaM does not recognize this action :(
Actions.AISoldiersLimit(PL,-1);
end else PLAYER[PL].Bonus := btNone;
text := text + '[$'+ States.PlayerColorText(PL)+']'+States.PlayerName(PL)+'[] = [$B9B9FF]'+States.WareTypeName(PL)+'|';
end;
ChoseRetribution(9);
Actions.ShowMSG(-1, '<$0>'); // Welcome message
Actions.ShowMSG(-1, text); // Players representation
end;
procedure OnTick;
var PL: Integer;
begin
//PRODUCTION ENHANCEMENT
i:= States.GameTime mod 640
if (i mod 10 = 0) and ((i mod 80) div 10 < 6) then MultiplyWares((i mod 80) div 10, i div 80);
//EXTRA BUILDING PLACEMENT
if States.GameTime = NextExtra then begin
{for h:=0 to 2 do begin
for i:=0 to 4 do begin
for j:=0 to 3 do begin
if States.UnitAt(ExtraBuildingTiles[h][i][j].X, ExtraBuildingTiles[h][i][j].Y) <> -1 then begin
Actions.GroupKillAll(States.UnitsGroup(States.UnitAt(ExtraBuildingTiles[h][i][j].X, ExtraBuildingTiles[h][i][j].Y)), false);
UnitsMustBeRemovedFirst:= true;
end;
end;
end;
end;}
if AlreadyRemovedUnits = false then begin
for h:=0 to 2 do begin
for i:= -5 to 5 do begin
for j:= -7 to 7 do begin
m:= RandomQuestPlace[h][0] + i;
n:= RandomQuestPlace[h][1] + j;
if States.UnitAt(m, n) <> -1 then begin
Actions.UnitKill(States.UnitAt(m, n), false);
UnitsMustBeRemovedFirst:= true;
end;
end;
end;
end;
end;
if UnitsMustBeRemovedFirst then begin
NextExtra:= NextExtra + 20;
UnitsMustBeRemovedFirst:= false;
AlreadyRemovedUnits:=true;
Exit;
end;
RandomQuestLoc:= States.KaMRandomI(High(RandomQuestPlace)+1);
RandomQuestType:= States.KaMRandomI(High(RandomQuestHouses)+1);
j:= Actions.GiveHouse(8, RandomQuestHouses[RandomQuestType], RandomQuestPlace[RandomQuestLoc][0], RandomQuestPlace[RandomQuestLoc][1]);
end;
// Statistics
if (States.GameTime mod UPDATE_OVERLAY_DELAY) = 0 then UpdateOverlay();
i:= States.GameTime mod 10
if (i < 8) then begin
if States.PlayerEnabled(i) then begin
// Schoolhouse
if not States.PlayerIsAI(i) then Recruits(i);
// Bonuses
if PLAYER[i].Bonus = btSurvivalists then Survivalist(i)
else if PLAYER[i].Bonus = btMasterCrafters then MasterCrafter(i);
for j:=0 to 5 do MultiplyWares(j, i);
end;
//EXTRAS
if ExtraActive[0] = true then begin //0 is Plague!
Extra_RandomDeath(ExtraRecipient, i);
if States.GameTime > ExtraEnd then begin
ExtraActive[0]:= false;
NextExtra:= States.GameTime + ExtraInterval - ExtraDuration;
end;
end;
if ExtraActive[1] = true then begin //1 is Abundance!
for j:=0 to 7 do begin
if Alliance[ExtraRecipient][j] = true then begin
FeedEveryUnit(States.PlayerGetAllUnits(j));
FillEveryInn(PlayerInns[j]);
AddExtraFoodToStore(j);
end;
end;
ExtraActive[1]:= false;
NextExtra:= States.GameTime + ExtraInterval;
end;
if ExtraActive[2] = true then begin //2 is God's Hand!
UnitTypeToDie[0]:= States.KamRandomI(24);
repeat
UnitTypeToDie[1]:= States.KamRandomI(24);
until UnitTypeToDie[0] <> UnitTypeToDie[1];
for j:=0 to 7 do begin
if Alliance[ExtraRecipient][j] = false then begin
KillRandomType(UnitTypeToDie[0], j);
KillRandomType(UnitTypeToDie[1], j);
end;
end;
ExtraActive[2]:= false;
NextExtra:= ExtraStart + ExtraInterval;
end;
if ExtraActive[3] = true then begin //3 is Conflagration!
for j:= 0 to 7 do begin
if Alliance[ExtraRecipient][j] = false then begin
HousesToDestroy:= States.PlayerGetAllHouses(j);
for k:=1 to (((High(HousesToDestroy)) * PortionToDestroy) div 100) do begin
BuildingToDestroy:= States.KaMRandomI(High(HousesToDestroy)+1);
case States.HouseType(HousesToDestroy[BuildingToDestroy]) of
11, 13, 18, 21, 27, 29: Dec(k);
else Actions.HouseDestroy(HousesToDestroy[BuildingToDestroy], false);
end;
end;
end;
end;
ExtraActive[3]:= false;
NextExtra:= States.GameTime + ExtraInterval;
end;
if ExtraActive[4] = true then begin //4 is Weapon Fair in Town!
for j:=0 to 7 do begin
if Alliance[ExtraRecipient][j] = true then begin
for k:=0 to High(PLAYER[j].Buildings.Barracks) do begin
GiveWeaponFair(PLAYER[j].Buildings.Barracks[k]);
end;
end;
end;
ExtraActive[4]:= false;
NextExtra:= States.GameTime + ExtraInterval;
end;
if ExtraActive[5] = true then begin //5 is REAL Peasants' Rebellion!
for j:=0 to 7 do begin
if Alliance[ExtraRecipient][j] = false then Actions.PlayerAllianceChange(9, j, true, false) else Actions.PlayerAllianceChange(9, j, true, true);
end;
Actions.PlayerAllianceChange(8, 9, true, true);
for j:=0 to High(RebelSpawnLoc) do begin
Actions.GiveGroup(9, 24, RebelSpawnLoc[j][0], RebelSpawnLoc[j][1], 4, (RebelNumber div Length(RebelSpawnLoc)), 8);
end;
ExtraActive[5]:= false;
NextExtra:= States.GameTime + ExtraInterval;
end;
end;
end;
Re: Error in script, please help!
PostPosted: 08 Nov 2017, 07:09
by grayter
I think this message appears, because you try to do something with group which is dead. I suggest you to check States.GroupDead in each case. You need to reproduce the problem, because code analysis is hard indeed. Try to find exact moment when problem appears. Maybe you will be able to localize problem in some function/procedure. It will be easier that way.
Re: Error in script, please help!
PostPosted: 08 Nov 2017, 07:48
by Rey
I checked source code - error happens in next block:
https://github.com/Kromster80/kam_remak ... s.pas#L862
It happens, when "//Enemy was killed, but target Group still exists", then we try to find another enemy from the same group, but there are no valid (not dead or dying) group members. Sounds like a bug for me. That should never happen.
If you could track the situation, when it happens, then I will be able to fix it.
Re: Error in script, please help!
PostPosted: 08 Nov 2017, 12:44
by Erdesz Balazs
Thank you!
I believe this issue is probably caused by a fact that I have a code which kills random enemy unit every second during a set period.
What I think happens is that there are 2 units in the group: one that was just killed by a unit, ordered to attack it. So group still exists, meaning next target will be selected. But - in the meantime - my script kills this unit, causing a crash. No?
What do you think?
If you want to find this script part search for the term “plague” under ontick.
I will have access to the crash replay this evening, so I will try to reproduce or observe the moment it happens.
Appreciate your help guys!
Re: Error in script, please help!
PostPosted: 09 Nov 2017, 18:40
by Erdesz Balazs
Sadly this was not the case. Noone was tough people that game.
I was able to get my hands on the replay.
Although, I cannot reproduce the error, nor can i get the replay to display what's happening. I get a warning message instead of the regular bug window.
But now I fully understand the source code: A unit had an attack order an another unit. This unit died while being targeted. Then code was looking for another foe, and this is where I get the error.
Re: Error in script, please help!
PostPosted: 09 Nov 2017, 20:03
by Rey
So it seems to be a quite rare error.
I can simply fix it removing Assert clause and just ignore that situation.
Ofc its better to figure it out why it happens exactly, but considering that it appears very rary I think this solution is good enought
Re: Error in script, please help!
PostPosted: 09 Nov 2017, 21:15
by Erdesz Balazs
If you want the replay, here you go.
By the way how do you modify source code?
Re: Error in script, please help!
PostPosted: 10 Nov 2017, 21:39
by Erdesz Balazs
The error happened again. So tomorrow I will try to look into it again.
I have a suggestion.
You should not remove the assert part. I think if the assert condition returns false, it should restart from the 'if'. So it checks again:
------------------------------------------------------------------------------
if (OrderTargetUnit = nil) and (OrderTargetGroup <> nil) then
begin
//Old enemy has died, change target to his comrades
U := OrderTargetGroup.GetNearestMember(Members[0].GetPosition);
Assert(U <> nil, 'We checked that Group is not dead, hence we should have a valid Unit'); (here, it goes back to the start)
OrderAttackUnit(U, False);
end;
------------------------------------------------------------------------------
What do you think?
Re: Error in script, please help!
PostPosted: 11 Nov 2017, 17:20
by Erdesz Balazs
I had time to investigate. I have the EXACT reason for the error.
My script kills random units every second. And, during this, it can kill units that haven't yet spawned to the playground. (For example, it can kill units that have already been trained but haven't left the barrack yet.)
Then when this group's units would vanish completely (e.g. last unit is killed), I get the error.
So the issue is: When these units die inside the barrack, they are most probably not removed from the group they were supposed to be part of. And then the game tries to look for a new target in the group, but the group is nonexistent anymore.
Re: Error in script, please help!
PostPosted: 12 Nov 2017, 07:43
by Rey
Thank you very much for your investigation!
I will look into it and try to fix it then
Re: Error in script, please help!
PostPosted: 17 Nov 2017, 19:58
by Rey
So the issue is: When these units die inside the barrack, they are most probably not removed from the group they were supposed to be part of. And then the game tries to look for a new target in the group, but the group is nonexistent anymore.
I checked the source code - and it looks like your theory is not correct, because soldier is not assigned to any group when he is inside Barracks. Group assign happens only when soldier went outside from Barracks.
I'll fix this error in a very simple way, as I said earlier.