Skip to content

Posts from Scripts

4.8 (8 ratings)
Auto-translated
Jewily, thank you, you're right, I really overlooked it. Now it gives an error on this line:
if GetHeroName(defH) == "Shadwyn" and GetHeroName(attH) == "Nur" then

Maybe I made a mistake with the "end" statements, but it doesn't seem like it.

In reply to Марта
User Avatar
Auto-translated
Martha
Now, an error is reported on the line
if GetHeroName(defH) == "Shadwyn" and GetHeroName(attH) == "Nur" then

Maybe I just miscalculated with the ends, but it doesn't seem like it.

Most likely, you made a mistake in the calculations, because the code snippet, if closed with an `end`, does not contain any syntax errors.
Review each block and check if `end` is placed everywhere, because if you didn't put `end` somewhere, the interpreter might not give you an accurate location of the missing `end`, that's just how it works.


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

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


                                                                                       
User Avatar
Auto-translated
Okay, let's simplify it for everyone. There's an error in your script. The error in my script was a single equals sign instead of two in the condition. To protect against such "terrible" typos (both mine and yours), I recommend reading the "Introduction to Lua" guide in the group files (it's in my signature). Ideally, you should at least understand the basics so you don't waste time on every syntax error.

Could you provide more specifics (I've already forgotten what your idea was)? Do you need a specific hero (Ilayia) to cast Lightning on all enemies at the start of any battle? And in battles involving the main villain (Nazir), not only should Ilayia cast Lightning, but Nazir should also cast Fireballs on all of Ilayia's creatures? All of this at the beginning of the battle, of course.
С уважением, }{0TT@6bI4
_________________
Группа картостроителей
Там ответы на вопросы, руководства, гайды и прочее
Discord-сервер "Герои 5: S.T.A.L.K.E.R"
Сервер по модификации "Герои 5: S.T.A.L.K.E.R"
_________________
In reply to }{0TT@6bI4
Auto-translated
The idea was that when Ilia (the main character) attacks the main villain (Nazir), her combat script would be disabled, and Nazir's script would be activated, even though he is defending.
I found my mistake in the script, but it still doesn't work, although the editor has stopped complaining.
I'm writing in the combat script, as a second script, after Ilia's script for casting Ice Block in each battle:

function Nur_battle()

local defH, attH = GetDefenderHero(), GetAttackerHero()

if GetHeroName(defH) == "Nur" and GetHeroName(attH) == "Shadwyn" then
local mana = GetUnitManaPoints(GetDefenderHero())
SetUnitManaPoints(GetDefenderHero(), 200);
repeat sleep(1) until GetUnitManaPoints(GetDefenderHero())==200
for i, creature in GetAttackerCreatures() do
startThread(UnitCastAimedSpell, GetDefenderHero(), 3, creature)
end;
SetUnitManaPoints(GetDefenderHero(), mana);
else
if GetHeroName(defH) == "Shadwyn" and GetHeroName(attH) == "Nur" then
local mana = GetUnitManaPoints(GetAttackerHero())
SetUnitManaPoints(GetAttackerHero(), 200);
repeat sleep(1) until GetUnitManaPoints(GetAttackerHero())==200
for i, creature in GetDefenderCreatures() do
startThread(UnitCastAimedSpell, GetAttackerHero(), 3, creature)
end;
SetUnitManaPoints(GetAttackerHero(), mana);
end;
end;
end;

But when Ilia attacks Nazir, she still casts Ice Block, and Nazir doesn't cast Lightning on her.

What am I doing wrong?)
Maybe Nazir needs to be defined somewhere in the MapScript?

Added 2 minutes ago
That is, I'm writing a second function in the combat script, of course, and not a second script.

Added 4 hours 8 minutes ago
And here's a second question.

I'm trying to set up a Town Portal system, like in Heroes 3.
There are no problems with the main character; she teleports to the right place.
But I would like all the heroes of the first player to be able to teleport through this script.
And here arises the problem of how to identify them - SetObjectPosition(heroName, x, y, floor) requires the name of a specific hero.
But how do I know who will appear in the tavern?

Since I don't know how to identify a hero without a name, I've been trying to copy scripts from the forum, but it doesn't seem to work.
I wrote in the beginning of the MapScript:

kot_heroes={"Shadwyn", "Raelag", "Urunir", "Ohtarig"};

Then I wrote a function:

function Portal_HaladF (heroname)
local Portal_Hero
for key, name in kot_heroes do
if name == heroName then
Portal_Hero=1
SetObjectPosition(heroName, 56, 90, 0);
sleep(1);
end;
end;
if not Portal_Hero then
print("не тот герой");
end;
end;

But all of this doesn't work; the game continues to require the name of the person who will teleport.

How do I write that the hero who used the object should teleport, if this hero belongs to the first player?
In reply to Марта
User Avatar
Auto-translated
Martha

Added 4 hours 8 minutes ago

How do I write the code so that the hero who activated the object is teleported, if that hero belongs to the first player?
So, a little bit of theory. Inside the parentheses, after the name of your function, is the magic word "heroname." This is the function's argument. Like in school, f(x) = x + 5. That is, you can pass different values to it, and the result is expected to be different. You need to pass the argument to the function manually if you call it yourself, but since visiting the object is already a defined event by the developers, the name of the hero and the name of the object will be passed to any function that you specify in the trigger. That is, by adding something like "object" after "heroname," you will also get the name of the object with which the interaction occurred.
So, following the logic I described, the "heroname" variable ALWAYS contains the name of the hero who approached the object. Therefore, all that remains is to write a check to see if this hero is a hero of the first player.
This can be done, if I'm not mistaken, with "GetObjectOwner(heroname) == 1." Well, of course, you should put this check in an "if" statement, and so on, but I hope you understand the logic.
What you wrote there will also work, for the heroes that you entered in the table, but in your check, you have "heroName," and in the argument, you have "heroname." Scripts are case-sensitive, like almost any programming language.
I understand why you made that mistake. The documentation states that "SetObjectPosition" first takes some "heroName," and that's why you put the same thing there, but this is just a "placeholder," it's the same as having "heroname" in the teleportation function. They could have written "arg1," or any other nonsense. It would just be even less clear to you. Therefore, when you pass an argument to any function, it does not have to be named the same as it is written in the function header. You can write any alphanumeric characters there if you need to.

Postscript:
It's better not to copy scripts from forums, but to take a good map, preferably one that you have played, which has scripts, and look at them. For example, the "Cursed" scenario contains many good scripts. It is also worth looking at the works of RedHeavenHero. And read the manual, because without it, it is very difficult to write scripts like yours.)

Added 1 hour 26 minutes ago
Trigger(OBJECT_TOUCH_TRIGGER,"portal","Portal_HaladF")
function Portal_HaladF(heroname)
if(GetObjectOwner(heroname) == 1) then
SetObjectPosition(heroname,56,90,0)
end
end

Here, instead of "portal" in the trigger, you give your own name, and everything will work.
And so that you understand, perhaps, what the trick is with naming arguments:

Trigger(OBJECT_TOUCH_TRIGGER,"portal","Portal_HaladF")
function Portal_Halad(red_flower)
if(GetObjectOwner(red_flower) == 1) then
SetObjectPosition(red_flower,56,90,0)
end
end

Instead of "heroname," "red_flower" appears. Do you agree that flowers have nothing to do with a hero? Of course, no one would name it that way because then you wouldn't be able to understand what the red flower is, but you need to understand the essence - the name itself is not important, the main thing is that it is inserted in the right place. If the trigger gives you the hero's name as the first argument, then it will give it to you regardless of how you name the variable.



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

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


                                                                                       
In reply to Jewily
Auto-translated
Jewily, while your function works (thank you, I'll keep that in mind), it doesn't work in my case.

Here's the thing: as I said, I'm trying to create something similar to the Town Portal system in Heroes 3, but using objects.
How can I do this? The only thing that comes to mind is using a QuestionBox.
Do you want to go to Halad? If the answer is "no," maybe you want to go to Torost, and so on. I have many towns on my map.

So, I can only attach a function to the object that contains a QuestionBox. And a different function is responsible for the actual teleportation.

I'm writing:

function Town_Portal_Tilgatal_Obelisk_F (heroname) -- this is the function for the obelisk of the town of Tilgatal, i.e., attached to the object.
if(GetObjectOwner(heroname) == 1) then
QuestionBox("/Maps/SingleMissions/L1/Portal_Halad.txt", "Portal_HaladF", "Town_Portal_Torost_question_F"); ----question: do you want to go to Halad? If yes, we teleport; if no, we offer Torost.
sleep(1)
else
print("wrong hero");
end;
end;
Trigger(OBJECT_TOUCH_TRIGGER, "town_portal_Tilgatal", "Town_Portal_Tilgatal_Obelisk_F");

And here is the function for the teleport itself:

function Portal_HaladF (heroname)
if(GetObjectOwner(heroname) == 1) then
SetObjectPosition(heroname, 56, 90, 0);
else
print("wrong hero");
end;
end;

The question is asked, but it doesn't teleport; instead, it writes Script Error: Object "1" does not exist.

Moreover, if I write in the second function:

function Portal_HaladF (heroname)
if heroname == "Shadwyn" then
SetObjectPosition("Shadwyn", 56, 90, 0);
sleep(1);
end;
end;

Then nothing is written, but the teleportation doesn't happen.

But if I simply write instead of the second function:
function Portal_HaladF (heroname)
SetObjectPosition("Shadwyn", 56, 90, 0);
sleep(1);
end;
- then everything works fine, it teleports to the right place.

But if I replace "Shadwyn" with heroname, it again writes Script Error: Object "1" does not exist.

What could be the reason for this? Why doesn't the check for the hero's name or belonging to the first player work in the second function?
In reply to Марта
User Avatar
Auto-translated
Martha

What could be the reason here? Why doesn't the check for the hero's name or their affiliation with the first player work in the second function?
Let me explain. QuestionBox passes the player number to the callback function (Portal_HaladF in your case) as the first argument, not the hero. It doesn't pass the hero at all. That's how the developers wrote it. Here's a solution:
 
function Town_Portal_Tilgatal_Obelisk_F (heroname) 
local player = GetObjectOwner(heroname)
if(player == 1) then
QuestionBox("/Maps/SingleMissions/L1/Portal_Halad.txt", "Portal_HaladF(player,[["..heroname.."]])", "Town_Portal_Torost_question_F(player,[["..heroname.."]])"); ----question: do you want to go to Halad? If yes - teleport, if no - offer Torost.
sleep(1)
else
print("not that hero");
end;
end;
Trigger(OBJECT_TOUCH_TRIGGER, "town_portal_Tilgatal", "Town_Portal_Tilgatal_Obelisk_F");

Then, we slightly modify the callback function, taking into account that the player is passed first

function Portal_HaladF (player,heroname)
local player = player + 0 -- I'm explaining a trick here. When you pass arguments directly in quotes, they are all passed as strings.
-- in player at the function's input, there's "1", and if you add zero to a string containing a number, it becomes a number (i.e., it will just be 1).
if(player == 1) then
SetObjectPosition(heroname, 56, 90, 0);
else
print("not that hero"); -- here, there's a check for the player, so it's more appropriate to write "not that player"
end;
end;

Now, let me explain what happened. You can pass arguments to the callback function manually (as in my example), but the standard argument passing is overwritten (I couldn't come up with a solution for this other than manually passing the parameters that the game was passing before. In this case, it's possible because only the player number is being passed). That is, we simply open the parentheses (yes, directly in quotes) and write the variables there. Important: numbers can be passed directly by simply specifying the variable in parentheses. This [["..heroname.."]] dinosaur is a way to pass a string. [[ ]] are also quotes. It's important that the quotes before the two dots match the quotes with which you open the
name of your function; otherwise, it won't work. This is a rather obscure thing, and it's worth reading about in Hottabych's guide.
P.S.
TalkBox would be suitable for your needs, but I'm afraid its use may cause difficulties.



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

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


                                                                                       
In reply to Jewily
Auto-translated
Unfortunately, it doesn't work. The game displays the following:

[Script Warning!] Value was NIL when getting global with name 'player'
Script Error: attempt to perform arithmetic on a nil value

P.S. I don't even know what TalkBox is.
In reply to Марта
User Avatar
Auto-translated
Martha
Unfortunately, it doesn't work. The game displays:

[Script Warning!] Walue was NIL when getting global with name 'player'
Script Error: attempt to perform arithmetic on a nil value

P.S. I don't even know what TalkBox is.
Perhaps I made a mistake somewhere. I will test it myself now and send it to you.

UPDATE:
Indeed, there was an issue with the player, which I have now fixed. Below is the fully working code snippet, tested by me.
All you have to do is add the same "dance" with [[ ]] to the player. I will say one thing: in your case, the second check is redundant. If you are only showing a message to one player, there is no point in even checking in the portal function whether it is the first player, because he is already the only one. But complete it with passing the player so that you understand how it works in the future. But in the code itself, as you can see, it is not needed.
SetObjectEnabled("testObj",nil)
Trigger(OBJECT_TOUCH_TRIGGER,"testObj","testF")
function testF(heroname)
local player = GetObjectOwner(heroname);
if(player == 1) then
QuestionBox(GetMapDataPath().."messages/broken_portal.txt","callbackF([["..player.."]],[["..heroname.."]])","callback_noF([["..player.."]],[["..heroname.."]])") -- arbitrary message from my folder.
end;
end;
function callbackF(player,heroname)
local x,y,floorID = GetObjectPosition(heroname) -- For testing, the hero is simply teleported to the same location
SetObjectPosition(heroname,x,y,floorID)
end;

function callback_noF(player,heroname)
local x,y,floorID = GetObjectPosition(heroname)-- For testing, the hero is simply teleported to the same location + 5 cells along all axes
SetObjectPosition(heroname,x+5,y+5,floorID)
end

Below is your already corrected code

function Town_Portal_Tilgatal_Obelisk_F (heroname) 
local player = GetObjectOwner(heroname)
if(player == 1) then
QuestionBox("/Maps/SingleMissions/L1/Portal_Halad.txt", "Portal_HaladF([["..player.."]],[["..heroname.."]])", "Town_Portal_Torost_question_F([["..player.."]],[["..heroname.."]])"); ----question: do you want to go to Halad? If yes - we teleport, if not - we offer Torost.
sleep(1)
else
print("not that hero");
end;
end;
Trigger(OBJECT_TOUCH_TRIGGER, "town_portal_Tilgatal", "Town_Portal_Tilgatal_Obelisk_F");
function Portal_HaladF (player,heroname)
SetObjectPosition(heroname, 56, 90, 0);
end;

I hope it works. My head isn't working well tonight - I apologize if there is some stupid mistake, check the logic of what is happening five times just in case :)



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

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


                                                                                       
In reply to Jewily
Auto-translated
Jewily, it works now. Thank you very much. And a second thank you for
SetObjectPosition(heroname,x+5,y+5,floorID)

I didn't know that was possible, and it will be useful for one of my quests right now.
Good night).

In reply to Марта
User Avatar
Auto-translated
Martha
Jewily, it’s working now. Thank you very much. And a second thank you for
SetObjectPosition(heroname,x+5,y+5,floorID)

I didn’t know you could do that, and it will be useful for one of my quests right now.
Good night).

I didn’t quite understand what you’re talking about, but you’re welcome. Good night.


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

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


                                                                                       
User Avatar
Auto-translated
Jewilly, there is a way to pass all the necessary data to the callback using upvalues:
function test()
  local importantValue = random(10)
  Trigger(4, "TestObject", "ImportantFunc")
  ImportantFunc = function(hero, obj)
    local value = %importantValue
    print(hero, obj, value)
  end
end
--This way, we pass the two original arguments + the important value from the parent function to the callback.
С уважением, }{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
Jewilly, there is a way to pass all the necessary data to the callback using upvalues:
function test()
  local importantValue = random(10)
  Trigger(4, "TestObject", "ImportantFunc")
  ImportantFunc = function(hero, obj)
    local value = %importantValue
    print(hero, obj, value)
  end
end
--This way, we pass the two original arguments + the important value from the parent function to the callback.
Oh, thank you very much. I tried everything myself, but I forgot about upvalues – I wasn't using them at the time when I started to understand things. I'll keep that in mind!


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

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


                                                                                       
In reply to Jewily
Auto-translated
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 intact. I'm trying to create guardians for teleporters, and given that I already have a huge number of these teleporters, writing a separate quest for each neutral monster would overload the game. If I create a sudden battle, how can 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);



And if these monsters are standing on the map, I don't even know where to attach the script. To the monsters themselves? It's unclear 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 whether it can be applied to monsters, and not to heroes.

Statistics

Welcome our newest member: Emil