Skip to content

Posts from Scripts

4.8 (8 ratings)
In reply to }{0TT@6bI4
User Avatar
3 years ago
Auto-translated
}{0TT@6bI4
In other words, you want to replace all creatures from 1 to k with a certain condition and luck, but you want this to happen
a) Inconsistently
b) Without repetition
c) With all k elements

Then you need an interesting algorithm:
local used_indexes = {}
for i=1, k do
repeat N=random(k)+1
until not used_indexes[N]
used_indexes[N] = 1;
--Actions with the creature with number N (not k!!)
end

 

It seems like you have some kind of error here - i is not passed anywhere. Or should it be n instead of i? I tried it in the game with your version, and the creatures spawned in the first two locations. Luckily, they have fixed spawn points, otherwise the game would crash due to lag 😆 

I made a few adjustments and ran it again - now the monsters spawn in different locations, but still in the same order, i.e., I run the function a second time, and it spawns the monsters in the same locations.

 

Yes, and here's another question. I have this condition in the function:

local type = random( 3 ) + 1
if ( WR_luck < 3 ) and ( type == 4 ) then
type = random( 2 ) + 1
end

Before I put these two conditions in parentheses, the game ignored them. Why? When should parentheses be used in conditions?

In reply to }{0TT@6bI4
User Avatar
3 years ago
Auto-translated
}{0TT@6bI4
Because the hero is not defined. Check in the console. The variable hero contains nil, and obviously, the IsHeroAlive check returns false.
How do I define hero then? I'm not very good with variables.
In reply to BlueHeavenHero
User Avatar
3 years ago
Auto-translated
BlueHeavenHero
How do you define a hero then? I'm not very good with variables.
local hero = "Duncan" - here's how you define a hero. But it's better to define it at the beginning of the script and without "local" so that you can use the hero in any function of the script later.
User Avatar
3 years ago
Auto-translated
`hero` is a very common name; it's better to make it a local variable. And you can assign it to a global variable at the beginning of the script, like this: `MAIN_HERO = "Duncan"`, as the developers did.
In reply to Азгалор
User Avatar
3 years ago
Auto-translated
Azgalor

It seems like there’s some kind of error here – i isn’t being passed anywhere. Or should i be n instead? I tried it in the game with your version, and creatures spawned in the first two locations. Good thing they have a fixed spawn, otherwise the game would crash from lag 😆

I made a few minor adjustments, ran it again – now the monsters spawn in different locations, but still in a list, i.e., I run the function a second time, and it spawns the monsters in the same locations.

I’ve solved the problem. I wrote this:
--All sorts of things before these lines
local n = random(length(creatures_positions))+1
local x = creatures_positions[n].x
local y = creatures_positions[n].y

--All sorts of things after these lines, k replaced with n

And now the random function works, and creatures spawn in random saved coordinates 😇 Still, a huge thank you for correcting the function for saving coordinates and helping with the respawn function!

In reply to Азгалор
User Avatar
3 years ago
Auto-translated
Azgalor
local hero = "Duncan" - this is how you define a hero. But it's better to define it at the beginning of the script and without "local" so that you can use "hero" in any function of the script later.
But, if "hero" in the script should be ANY hero of the player?
User Avatar
3 years ago
Auto-translated
If your function is called by a region trigger, then specify `hero` as the accepted parameter, and you can then use `hero` everywhere.
In reply to Азгалор
User Avatar
3 years ago
Auto-translated
Azgalor
I've fixed the issue. I wrote the following:
--All sorts of things before these lines
local n = random(length(creatures_positions))+1
local x = creatures_positions[n].x
local y = creatures_positions[n].y

--All sorts of things after these lines, k has been replaced with n

Now the random function works, and the creatures spawn at random saved coordinates 😇 Still, a huge thank you for correcting the function that saves the coordinates and for helping with the respawn function!


I still don't understand your task, but never mind. My code iterates through all k creatures (while i is not needed) and generates a random index k until it exists in the array of indices. As soon as it doesn't, it works with the creature with the generated index k.

The reason for this check with a loop is that a simple random function (like yours) can produce duplicate values, and as I understand it, that shouldn't happen. Perhaps I misunderstood.

And in general, it's very strange that it doesn't work for you and generates in two places. I ran some test prints for k=100, and it generated a bunch of values, all different (well, I didn't scroll through all of them).
In reply to }{0TT@6bI4
User Avatar
3 years ago
Auto-translated
}{0TT@6bI4

I still don't understand anything about your task, but okay. My code iterates through all k creatures (including i) and generates a random index k until it exists in the array of indices. As soon as it doesn't, it works with the creature with the generated index k.

The reason for the check with a loop is because a simple random number generator (like yours) can produce duplicate values, which, as I understand it, shouldn't happen. I might be wrong.

In general, it's very strange that it doesn't work for you and generates in two places. I ran some test prints for k=100, and it generated a lot of different values (well, I didn't scroll through all of them).
Honestly, I understand even less now. If I understood, I wouldn't ask for help 😅. Anyway, here is the final version of this script for spawning, I just finished it and moved on to something else (I'm not touching the coordinate saving anymore):
function RespawnUnitsByLuck()
if ( GetDate(WEEK) == 2 ) and ( GetDate(DAY_OF_WEEK) == random(6) + 1 ) then
local WR_luck = GetHeroStat(WR, STAT_LUCK)
local respawns_types = { CREATURE_AIR_ELEMENTAL, CREATURE_PHOENIX, CREATURE_AIR_ELEMENTAL, CREATURE_PHOENIX }
local respawns_quantities = { 100 * diff, 10 * diff, 100 * diff, 4 * diff }
local respawns_mood = {3, 1, 3, 0}
local respawns_courage = {1, 2, 1, 0}
local respawns_num = 0
local previous_pos = {}
local respawns_id = 0

--Reminder about difficulties to calculate multipliers from difficulties: diff = 0.5(easy), 2(normal), 4(veteran), 6(heroic), 10(hardcore)
local CanRespawnUnitsByLuck = random(100) + ((10*(WR_luck+1)) * mod((WR_luck+1),diff))
if CanRespawnUnitsByLuck >= mod(70,(WR_luck+2)) + (60+diff) then
print("The random number is "..CanRespawnUnitsByLuck, ", which is greater than or equal to the threshold. Spawning units...")
elseif CanRespawnUnitsByLuck < mod(70,(WR_luck+2)) + (60+diff) then --( 50 + (10+diff) ) then
print("The random number is "..CanRespawnUnitsByLuck, ", which is below the threshold. Not spawning anything, exiting the function...")
return
end

for i = 1, 20 + diff do
local n = random(length(creatures_positions))+1
local x = creatures_positions[n].x
local y = creatures_positions[n].y
local floor = 0;
local badpos = 0;

if IsObjectExists("m"..n) or IsObjectExists("respawns"..n) then
badpos = 1
end

if ( badpos == 0 ) and ( IsTilePassable( x, y, floor ) ) then
respawns_num = respawns_num + 1
if respawns_num == 20 + diff then
print("Maximum number of units spawned. Exiting the spawner.")
return --if more than 20+difficulty units have been spawned, then exit, otherwise there will be a huge overspawn
end

local type = random( 3 ) + 1
if ( WR_luck < 3 ) and ( type == 4 ) then
type = random( 2 ) + 1
end
if ( WR_luck >= 5 ) then
respawns_quantities = { 200 * diff, 4 * diff, 200 * diff, 4 * diff }
respawns_courage = {1, 0, 1, 0}
type = random( 2 ) + 2
end
local creaturetype = respawns_types[ type ]
local quantity = respawns_quantities[ type ]
local mood = respawns_mood[ type ]
local courage = respawns_courage[ type ]
local respawnsname = 'respawns' .. n;
CreateMonster( respawnsname, creaturetype, quantity, x, y, floor, mood, courage, random( 360 ) );
end;
end;
if respawns_num == 0 then
print("No creatures were spawned. Probably, all spawn points are occupied.")
else
print("Spawning completed. Creatures spawned: "..respawns_num)
end;
end;
end;
User Avatar
3 years ago
Auto-translated
Good day! I need help with a script. I created a special ability for a hero, so that if, during a battle, less than 30% of creatures remain in his army, Death Wraiths are summoned in the amount of HeroLevel * 0.05. But I doubt that this will work...
function Start()
if GetHeroName(GetAttackerHero())=="HafadNecro" then
side=ATTACKER
aside=DEFENDER
start_creatures=CountCreatures(side)
elseif GetHeroName(GetDefenderHero())=="HafadNecro" then
side=DEFENDER
aside=ATTACKER
start_creatures=CountCreatures(side)
end
end
function CountCreatures(_side)
local fc_count=0
for key, element in GetCreatures(_side) do
fc_count=fc_count+GetCreatureNumber(element)
end
return fc_count
end
function UnitDeath(unit)
sleep(4)
if intg(start_creatures*0.30)<=CountCreatures(side) then
for key, name in GetCreatures(aside) do
SummonCreature(side, CREATURE_WRAITH, 0.05*GetHeroLevel("HafadNecro"), 12, 2)
end;
end;
end;

User Avatar
3 years ago
Auto-translated
I wonder how it will summon 0.05 * 8, i.e., 0.4 Banshees. You either need to add ceil or floor, otherwise it will spawn zero units. Overall, it should work.
User Avatar
3 years ago
Auto-translated
Yes, the number should definitely be higher. At least 0.3 times the hero's level. That is, at level 40, it will be approximately 12 banshees, which is quite small; it probably needs to be even higher.

SummonCreature summons creatures correctly in a free, random location, without coordinates.
In reply to AstralLein
User Avatar
3 years ago
Auto-translated
AstralLein
Yes, the number should definitely be higher. At least 0.3 * hero level. So, at level 40, there will be approximately 12 banshees, which is quite small; it probably needs to be even more.

SummonCreature summons to a free random point without coordinates.
I will change it to a larger number.

Added 3 minutes later
A problem has arisen! In the original Heroes Campaigns, in the fifth mission, after Godric frees Isabelle, Agrail attacks the Castle. I decided to implement the same function in my scenario, but the dialogue scene plays BEFORE Vittorio attacks the Castle!
function ChristianAttack()
DeployReserveHero("Christian", 98, 108, 0)
sleep(10)
MoveHero("Christian", 126, 139, -1)
if IsHeroAlive("Hafad") then
if IsHeroAlive("Christian") then
if GetObjectOwner("castle") == PLAYER_2 then
SetObjectiveState("prim5", OBJECTIVE_FAILED, 1)
sleep(10)
loose()
else StartDialogScene("/DialogScenes/FallenKnight/S3/DialogScene.xdb#xpointer(/DialogScene)")
sleep(1)
SetObjectiveState("prim5", OBJECTIVE_COMPLETED, 1)
SetObjectiveState("prim6", OBJECTIVE_ACTIVE, 1)
end;
end;
end;
end;
In reply to BlueHeavenHero
User Avatar
3 years ago
Auto-translated
BlueHeavenHero
I've encountered a problem! In the original Heroes Campaign, in the fifth mission, after Godric frees Isabelle, Agrail attacks the Castle. I decided to implement the same feature in my scenario, but the dialogue scene plays BEFORE Vittorio attacks the Castle!
This is because, according to your conditions (else), if the object (town?) "castle" does not belong to player 2, the video is triggered.

If you need it to trigger after the town is captured, you need to add a script for town capture with activation of the function through OBJECT_CAPTURE_TRIGGER, where we check who captured it and who the new owner is, and then trigger the video if the town was captured by the player who owns the hero you need. Something like this:
function TownCaptured( oldowner, newowner )
if IsHeroAlive("Hafad") then
if IsHeroAlive("Christian") then
if ( newowner == GetObjectOwner("Christian") ) then
StartDialogScene("/DialogScenes/FallenKnight/S3/DialogScene.xdb#xpointer(/DialogScene)")
sleep(1)
SetObjectiveState("prim5", OBJECTIVE_COMPLETED, 1)
SetObjectiveState("prim6", OBJECTIVE_ACTIVE, 1)
elseif newowner == PLAYER_2 then
SetObjectiveState("prim5", OBJECTIVE_FAILED, 1)
sleep(10)
loose()
end
end
end
end

Trigger( OBJECT_CAPTURE_TRIGGER, "castle", "TownCaptured" );

Thus, after MoveHero from the function with the hero respawn, you can remove the conditions and actions.

In reply to Азгалор
User Avatar
3 years ago
Auto-translated
Azgalor

Because, according to the condition (else), if the object (city?) "castle" does not belong to player 2, then the video is played.

If you need it to play after capturing the city, you need to add a script for capturing the city with the activation of a function through OBJECT_CAPTURE_TRIGGER, where we check that the city has been captured and who the new owner is, and then we will play the video if the city was taken by the player who owns the hero you need. Something like this:
function TownCaptured( oldowner, newowner )
if IsHeroAlive("Hafad") then
if IsHeroAlive("Christian") then
if ( newowner == GetObjectOwner("Christian") ) then
StartDialogScene("/DialogScenes/FallenKnight/S3/DialogScene.xdb#xpointer(/DialogScene)")
sleep(1)
SetObjectiveState("prim5", OBJECTIVE_COMPLETED, 1)
SetObjectiveState("prim6", OBJECTIVE_ACTIVE, 1)
elseif newowner == PLAYER_2 then
SetObjectiveState("prim5", OBJECTIVE_FAILED, 1)
sleep(10)
loose()
end
end
end
end

Trigger( OBJECT_CAPTURE_TRIGGER, "castle", "TownCaptured" );

Thus, after MoveHero from the function with the hero's respawn, the conditions and actions can be removed)

You didn't quite understand me. After a human player captures the city, a quest to hold the city is activated. Vittorio is placed on the map and begins to move towards our city. If we defeat Vittorio, a video is played. If Vittorio captures the city, we lose.
By the way, a similar problem arose with another function - a cutscene is played, then a battle begins, and AFTER the battle, a text message appears. But - the cutscene is played, and the text message appears BEFORE the battle. How can this be fixed?

Statistics

Welcome our newest member: recijeb