Skip to content

Posts from Scripts

4.8 (8 ratings)
In reply to Марта
User Avatar
Auto-translated
Martha
Another question. How can I track the results of a battle with neutral monsters?
I need a script for Heroes 1 that would check whether certain monsters died or survived after a battle, and depending on the result, allow me to destroy, say, a REGION_ENTER_AND_STOP_TRIGGER, or leave it.
I'm trying to create guardians for teleporters, and given that I already have a lot of teleporters, writing a separate quest for each neutral creature would overload the game.

If it's a random battle, how do I record the results after

function guard_Tilgatal_battle_F(heroname)
local player = GetObjectOwner(heroname)
if(player == 1) then
StartCombat(heroname, nil, 3, 80, 12, 158, 5, 142, 12, nil, nil, nil);

the battle?

And if these monsters are on the map, I don't even know where to attach the script.
To the monsters themselves? It's not clear what to write.

I tried to do something with COMBAT_RESULTS_TRIGGER, but I don't understand how it works, and I don't understand at all if it can be applied to monsters, and not to heroes.
First, about StartCombat. If you write StartCombat(heroname, nil, 3, 80, 12, 158, 5, 142, 12, nil, "combatCallback", nil, nil),
the combatCallback(heroname, result) function will receive the hero's name and the result. If result is nil, the hero lost; if it's not nil, the hero won. You can then create conditions based on this data.

Now, about the random battle. You register a trigger: Trigger(COMBAT_RESULTS_TRIGGER, "MyCombatResultsHandler")
In the MyCombatResultsHandler(combatIndex) function, after any battle, you'll receive a unique battle index – a number that characterizes that specific battle.
In it, you check if(GetSavedCombatResult(combatIndex) == COMBAT_RESULT_WIN) – this means the battle ended with someone winning.
Then, check if(GetSavedCombatArmyPlayer(combatIndex, 0) == PLAYER_NONE and GetSavedCombatArmyPlayer(combatIndex, 1) == 1). GetSavedCombatArmyPlayer(combatIndex, 1/0) is a function that returns the player number, either the loser or the winner. If the second parameter is 0, it's the loser; if you pass 1, it's the winner.
If all the above checks pass, it means your first player fought the neutrals and won.
Now, about how to check for specific killed monsters. First, you need to give them a script name in the editor; I assume you know how.
Then, there are two ways: one is complex, designed for large maps with many such monsters to check, and it will be difficult for you to understand, although it is correct from a programming and logic point of view. The other is simpler.
Let's go with the "simpler" approach, to save time. At the beginning of the map file, create n variables, one for each squad to check, for example:
ALIVE_GUARD_1 = not nil
ALIVE_GUARD_2 = not nil
...
ALIVE_GUARD_N = not nil

Then, simply write a bunch of checks like this:

if(ALIVE_GUARD_N == not nil) then
if(IsObjectExists("GUARD_N") == nil) then -- If this passes, it means your guard died.
ALIVE_GUARD_N = nil -- Be sure to indicate that the condition should no longer be checked.
... -- Do your various actions here.
end
end

That's roughly the technology. I don't have ready-made scripts on this topic, so you'll have to figure it out.
To avoid getting lost in the names of the guards, you can create a convenient table instead of that list of variables,
if you know how. If not, explaining it will again take a long time, and it is described in the manual.


Не уходи безропотно во тьму,
Будь яростней пред ночью всех ночей,
Не дай погаснуть свету своему!

Хоть мудрый знает – не осилишь тьму
Во мгле словами не зажжёшь лучей –
Не уходи безропотно во тьму.


                                                                                       
In reply to Jewily
Auto-translated
Guys, sorry, I haven't been on this forum for two days, but I'm still here, and I still need help. I have a question. There is REGION_ENTER_AND_STOP_TRIGGER, which moves objects depending on whether the nearest Castles belong to the first player. Is it possible to add several Castles to this function, or do I need to draw a separate region for each individual object and Castle? That is, I am writing: function Beacon_Tilgatal_F () if GetObjectOwner("Dungeon_1") == 1 then SetObjectPosition("Port_Tilgatal", 81, 133, 0); sleep(1); print("Castle Tilgatal is ours"); sleep(1); else SetObjectPosition("Port_Tilgatal", 127, 142, 1); sleep(1); print("Castle Tilgatal is not ours"); sleep(1); end; end; Trigger(REGION_ENTER_AND_STOP_TRIGGER, "Beacon_Tilgatal_trigger", "Beacon_Tilgatal_F"); And everything is fine here, the object moves to where it needs to. But is it possible to attach other Castles and objects to this trigger, in the same function? How can I do that? That is, attach this to the first snippet: if GetObjectOwner("Dungeon_2") == 1 then SetObjectPosition("Port_Halad", 63, 104, 0); sleep(1); print("Castle Halad is ours"); sleep(1); else SetObjectPosition("Port_Halad", 127, 142, 1); sleep(1); print("Castle Halad is not ours"); sleep(1); And this one? if GetObjectOwner("Dungeon_3") == 1 then SetObjectPosition("Port_Torost", 104, 105, 0); sleep(1); print("Castle Torost is ours"); sleep(1); else SetObjectPosition("Port_Torost", 127, 142, 1); sleep(1); print("Castle Torost is not ours"); sleep(1); P.S. Jewily, I barely managed to figure out the sudden attacks, thank you very much. I haven't figured out the monsters on the map yet, but for now, regions are enough for me.
User Avatar
Auto-translated

Martha, if (GetObjectOwner("Dungeon_1") == 1) and (GetObjectOwner("Dungeon_2") == 1) then

For example

In reply to Азгалор
Auto-translated
Azgalor, no, that won't work; you can't assign Castles and objects in bulk. Different Port objects are associated with different Castles. The first and third Castles can belong to the first player, while the second Castle belongs to someone else. I don't need a check to see if all Castles are joined at once; I need a script that allows different owners to have different Castles, and the positions of the objects change accordingly.

Added 49 minutes ago
I would like something like this:

function Beacon_Tilgatal_F ()
 if (GetObjectOwner("Dungeon_1") == 1) then
  SetObjectPosition("Port_Tilgatal", 81, 133, 0);
  sleep(1);
  print("our Tilgatal Castle");
  sleep(1);

else
if (GetObjectOwner("Dungeon_1") == 2)
 or (GetObjectOwner("Dungeon_1") == 3)
 or (GetObjectOwner("Dungeon_1") == 4)
 or (GetObjectOwner("Dungeon_1") == 5)
 or (GetObjectOwner("Dungeon_1") == 6)
 or (GetObjectOwner("Dungeon_1") == 7)
 or (GetObjectOwner("Dungeon_1") == 8)
 or (GetObjectOwner("Dungeon_1") == 0) then
  SetObjectPosition("Port_Tilgatal", 125, 142, 1);
  sleep(1);
  print("not our Tilgatal Castle");
  sleep(1);

 else
  print("somehow need to attach the second Castle here");
 sleep(1);
 end;
  end;
   end;

   Trigger(REGION_ENTER_AND_STOP_TRIGGER, "Beacon_Tilgatal_trigger", "Beacon_Tilgatal_F");

But it doesn't work at all.
User Avatar
Auto-translated

Martha, I apologize, I didn't pay close enough attention to what you needed... Yes, of course, it's possible. We'll add extra checks to the first function, i.e.:

function Beacon_Tilgatal_F()
if GetObjectOwner("Dungeon_1") == 1 then
SetObjectPosition("Port_Tilgatal", 81, 133, 0);
sleep(1);
print("Tilgatal Castle is ours");
sleep(1);
else
SetObjectPosition("Port_Tilgatal", 127, 142, 1);
sleep(1);
print("Tilgatal Castle is not ours");
sleep(1);
end;
if GetObjectOwner("Dungeon_2") == 1 then
SetObjectPosition("Port_Halad", 63, 104, 0);
sleep(1);
print("Halad Castle is ours");
sleep(1);
else
SetObjectPosition("Port_Halad", 127, 142, 1);
sleep(1);
print("Halad Castle is not ours");
sleep(1);
end;
if GetObjectOwner("Dungeon_3") == 1 then
SetObjectPosition("Port_Torost", 104, 105, 0);
sleep(1);
print("Torost Castle is ours");
sleep(1);
else
SetObjectPosition("Port_Torost", 127, 142, 1);
sleep(1);
print("Torost Castle is not ours");
sleep(1);
end;
end;

 

Martha
if (GetObjectOwner("Dungeon_1") == 2)
 or (GetObjectOwner("Dungeon_1") == 3)
 or (GetObjectOwner("Dungeon_1") == 4)
 or (GetObjectOwner("Dungeon_1") == 5)
 or (GetObjectOwner("Dungeon_1") == 6)
 or (GetObjectOwner("Dungeon_1") == 7)
 or (GetObjectOwner("Dungeon_1") == 8)
 or (GetObjectOwner("Dungeon_1") == 0) then

This check for ownership by players can be shortened to this (since you need only one player to own the Castles):

if (GetObjectOwner("Dungeon_1") ~= 1) then --If the Castle does not belong to the first player, then our authority ends here
In reply to Азгалор
Auto-translated
Unfortunately, it's not working again. It only moves the first object, Port_Tilgatal, and only when the Castle belongs to the first player or when an enemy captures it. The other two objects are not moved, and no messages are printed. Thanks for the simplification; I knew there had to be something better than my convoluted code. Added after 1 hour 58 minutes: Yes, here it is, the breakthrough! This way, all three work. ``` function Beacon_Tilgatal_F () if GetObjectOwner("Dungeon_1") == 1 then SetObjectPosition("Port_Tilgatal", 81, 132, 0); sleep(1); print("Tilgatal Castle is ours"); sleep(1); elseif (GetObjectOwner("Dungeon_1") ~= 1) then SetObjectPosition("Port_Tilgatal", 125, 142, 1); sleep(1); print("Tilgatal Castle is not ours"); sleep(1); end; if GetObjectOwner("Dungeon_2") == 1 then SetObjectPosition("Port_Halad", 63, 104, 0); sleep(1); print("Halad Castle is ours"); sleep(1); elseif (GetObjectOwner("Dungeon_2") ~= 1) then SetObjectPosition("Port_Halad", 126, 141, 1); sleep(1); print("Halad Castle is not ours"); sleep(1); end; if GetObjectOwner("Dungeon_3") == 1 then SetObjectPosition("Port_Torost", 104, 105, 0); sleep(1); print("Torost Castle is ours"); sleep(1); elseif (GetObjectOwner("Dungeon_3") ~= 1) then SetObjectPosition("Port_Torost", 126, 143, 1); sleep(1); print("Torost Castle is not ours"); sleep(1); end; end; Trigger(REGION_ENTER_AND_STOP_TRIGGER, "Beacon_Tilgatal_trigger", "Beacon_Tilgatal_F"); ``` Thank you, Azgalor, I definitely wouldn't have figured it out without you.
User Avatar
Auto-translated
Martha, I'm glad you managed to achieve the desired result) Although it's strange, because the code I wrote was working. I tested it on a map with creatures - they teleported to different locations depending on the affiliation of the cities, and the print statements worked...
Auto-translated
Help me, kind people, with another script. The idea is that initially, only the second player should be able to pass through the garrison, and under certain conditions, the first player should also be able to. But the script doesn't work from the very beginning. If you write in MapScript: SetObjectEnabled("Garnizon_1", nil); print("garrison disabled"); and then: function Garrison_1_Block_F() SetObjectEnabled("Garnizon_1", true); sleep(1); print("garrison enabled"); sleep(1); end; Trigger(OBJECT_TOUCH_TRIGGER, "proba", "Garrison_1_Block_F"); - then everything works fine. But if you write: SetObjectEnabled("Garnizon_1", nil, 1, 3, 4, 5, 6, 7, 8); ---or false, I tried print("garrison disabled"); function Garrison_1_Block_F() SetObjectEnabled("Garnizon_1", true, 1); sleep(1); print("garrison enabled for the first player"); sleep(1); end; Trigger(OBJECT_TOUCH_TRIGGER, "proba", "Garrison_1_Block_F"); - then the garrison is disabled for the second player as well, and it doesn't turn on for the first player either. As always, what am I doing wrong? And specifically, how do I disable the garrison from the very beginning for everyone except the second player?
In reply to Марта
User Avatar
Auto-translated
Martha

Specifically, how do you disable the garrison for everyone except the second player from the very beginning?
Good evening. The SetObjectEnabled function does not accept anything as a third parameter, meaning you cannot specify which player to block. An object can either be enabled or disabled. Regarding your script, I can suggest the following:
-- Create a single-cell region, one cell in front of the garrison
Trigger(REGION_ENTER_WITHOUT_STOP_TRIGGER,"GARRISON_REG","GarrisonCheck")
-- Create an array of "Banned" players
GARRISON_BANNED_PLAYERS = {
2,
-- If necessary, add the desired players here.
-- If you need to add to the script, write it in the appropriate place: GARRISON_BANNED_PLAYERS[length(GARRISON_BANNED_PLAYERS)] = "Player number to block"
}
-- If you need to remove a player from the array, write the following function (it already exists in the RedHeavenHero library; it's better not to reinvent the wheel)
-- The function below removes from the array in a rather crude way, but it should work for you.
-- In the place where you need to remove, write: GARRISON_BANNED_PLAYERS = arrayShiftByValue(GARRISON_BANNED_PLAYERS,"Player number to remove")
-- You will receive an array that no longer contains the specified player, or rather, with nil instead of the number
function arrayShiftByValue(array,value)
for index,element in array do
if(element == value) then
array[index] = nil
end
end
return array
end

function GarrisonCheck(heroname)
local player = GetObjectOwner(heroname)
if(contains(GARRISON_BANNED_PLAYERS,player) == not nil) then
SetObjectEnabled("GARRISON_NAME",nil)
else
SetObjectEnabled("GARRISON_NAME",not nil)
end
end

In common parlance, this is called a workaround, but it should work without any problems. When a unit approaches, we simply check the player and block the garrison if it is a player who is banned; otherwise, we remove the block.



Не уходи безропотно во тьму,
Будь яростней пред ночью всех ночей,
Не дай погаснуть свету своему!

Хоть мудрый знает – не осилишь тьму
Во мгле словами не зажжёшь лучей –
Не уходи безропотно во тьму.


                                                                                       
In reply to Jewily
Auto-translated
Jewily, thank you very much, I seem to have already figured out a simpler way, but now I have a different problem – I can't test it. Here's the script: SetObjectEnabled("Garnizon_1", nil); print("garrison disabled"); function Garrison_1_Block_F() if GetCurrentPlayer() == 2 then SetObjectEnabled("Garnizon_1", true, 2); sleep(1); print("garrison enabled for the second player"); sleep(1); else if GetCurrentPlayer() == 1 then SetObjectEnabled("Garnizon_1", true, 1); sleep(1); print("garrison enabled for the first player"); sleep(1); else SetObjectEnabled("Garnizon_1", nil); print("you are neither the first nor the second player"); end; end; end; Trigger(OBJECT_TOUCH_TRIGGER, "Garnizon_1", "Garrison_1_Block_F"); If I test it personally, playing as the first, second, and third player, everything works. But the problem is that I can't make the computer-controlled players try to go through this garrison. I've tried all sorts of lures on the map, but they won't go through those gates, no matter what. I even placed unprotected towns nearby, but they still won't go there. How can I make these sheep try to go through there?
In reply to Марта
User Avatar
Auto-translated
Martha


How can I make these sheep try to go there?
First of all, thank you for the amusing discovery; I wouldn't have thought to put an undocumented argument into a function, but oh well. Regarding the bots, I probably won't be able to give you any specific advice, as I haven't tried it in practice yet, BUT
SetAIPlayerAttractor("Object Name","Bot Player Number",1)

This will set the computer's priority to visit a specific object; you can experiment with it.

 



Не уходи безропотно во тьму,
Будь яростней пред ночью всех ночей,
Не дай погаснуть свету своему!

Хоть мудрый знает – не осилишь тьму
Во мгле словами не зажжёшь лучей –
Не уходи безропотно во тьму.


                                                                                       
In reply to Jewily
Auto-translated
Jewily, thank you, I'll try it now. I'll set something up and write the script.

P.S. Your method worked, but here's the catch – the second one passes normally, and for some reason, the third one follows him, he can also pass.
And only the first player can't pass until he fulfills the condition (which I already managed to set), then he can too.
Okay, I managed by drawing a trigger around the garrison that is impassable for all players except the first and second.
But in general, it's strange why it works that way.

Thank you for your help.
By the way, about the undocumented argument, I didn't understand anything, I just removed the parentheses)).
P.P.S. Well, never mind, it seems to have stopped working for me too.
Okay, I had to do it through a trigger, as you said, but I think I managed without a list.
User Avatar
Auto-translated
Create a region that is three cells thick (so that the approach to the garrison is blocked by the region from both entrances). Then, block the region for all the players you want... Whoever can pass will pass through peacefully and take the garrison.
С уважением, }{0TT@6bI4
_________________
Группа картостроителей
Там ответы на вопросы, руководства, гайды и прочее
Discord-сервер "Герои 5: S.T.A.L.K.E.R"
Сервер по модификации "Герои 5: S.T.A.L.K.E.R"
_________________
In reply to }{0TT@6bI4
User Avatar
Auto-translated
}{0TT@6bI4
Create a region that is three cells thick (so that the approach to the garrison is blocked by the region from both entrances). Then, block the region for all the players you want... Whoever can pass will pass through and take the garrison.
Yes, that's easier. Khottabych even helps out during his vacation.
Otherwise, the esteemed Martha writes with ZYSHKAMI instead of new messages, and I don't even want to go into the thread.


Не уходи безропотно во тьму,
Будь яростней пред ночью всех ночей,
Не дай погаснуть свету своему!

Хоть мудрый знает – не осилишь тьму
Во мгле словами не зажжёшь лучей –
Не уходи безропотно во тьму.


                                                                                       
In reply to Jewily
Auto-translated
Hottabych, that's exactly what I did. But since I already have a lot of garrisons, and for each one, I have to create three triggers (and in some cases, even from both sides), I'm afraid my map will crash due to the sheer number of triggers.

So, here's a question for everyone.
Is it possible to link a condition, say, for displaying text, not to a region, object, or battle, but simply to the completion of SetObjectiveProgress, or to picking up an artifact, or to both?
I've been trying for about 12 hours, but nothing works.
No matter which trigger I try to attach to this:

function Laszlo_goodbye_F(heroname)
if GetObjectiveProgress ("Quest_Zubec", 1) == 3 then
sleep(2);
MessageBox ("/Maps/SingleMissions/L1/Parol_Zubec1.txt");
end;
end;

- the game just doesn't recognize it.

I tried:

if GetObjectiveState("Quest_Zubec", 1) == 2 and GetObjectiveProgress ("Quest_Zubec", 1) == 3 then
- it doesn't recognize it.

I tried giving an artifact - it still doesn't recognize it.

I tried using OBJECTIVE_STATE_CHANGE_TRIGGER - it doesn't recognize it, although maybe I'm writing it incorrectly.

What should I do about this? Will I have to create another region for REGION_ENTER_AND_STOP_TRIGGER and somehow force the main hero into it?

Statistics

Welcome our newest member: Emil