Whether fire, spikes, etc. I imagine that someone has already thought of a way, but I can't think about one with the options I have in the manual right now.
I have some scripts used for enemies avoidance but not directly related to traps. At first sight I think that you can use theWhether fire, spikes, etc. I imagine that someone has already thought of a way, but I can't think about one with the options I have in the manual right now.
findtarget
function inside the thinkscript for enemies and then changing their aimove to avoid
below a defined range compared with the trap's position. Above a this limit the aimove returns to normal
.findtarget
will not work. You can use the own animation's range properties for the findtarget function, I suggest to points to the walk animation in the animnum
.changeentityproperty(self, "aimove", openborconstant("AIMOVE1_AVOID"));
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE"));
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_NORMAL"));
void target = findtarget(self, openborconstant("ANI_WALK"));
anim walk
range 0 485
rangea -999 999
rangez -999 999
loop 1
delay 16
offset 62 125
bbox 50 55 23 74
@cmd clearL
frame data/chars/heroes/axel/idle00.png
frame data/chars/heroes/axel/idle01.png
frame data/chars/heroes/axel/idle02.png
frame data/chars/heroes/axel/idle03.png
frame data/chars/heroes/axel/idle00.png
frame data/chars/heroes/axel/idle01.png
frame data/chars/heroes/axel/idle02.png
frame data/chars/heroes/axel/idle03.png
Whether fire, spikes, etc. I imagine that someone has already thought of a way, but I can't think about one with the options I have in the manual right now.
This is what I used - ondoattackscript on a certain enemy, against a certain attack type (attack17).I was going to suggest using ondoattackscript to cancel damage from traps while changing animation to a dodge trap animation but this might only work against certain traps.
void main()
{
void self; // Entity running event
void other; // Entity attacking or receiving vs. self.
int which; // Attacker or defender event?
int hit_by_id; // Entity ID of entity attack hit.
int attack_id; // Entity ID of entity that performed attack.
int type;
type = getlocalvar("attacktype");// Get attack type
self = getlocalvar("self");
other = getlocalvar("other");
which = getlocalvar("which");
// Is this a defending event?
if(which == 0)//openborconstant("EXCHANGE_RECIPIANT")
{
// IDs are not the same? This is how we prevent repeat
// hits from the same attack.
hit_by_id = getentityproperty(self, "hitbyid");
attack_id = getlocalvar("attackid");
// Different attack ID?
if(hit_by_id != attack_id)
{
// Is this the attack type we want? If so,
// set lasthit 0 (engine ignores attack hit).
if(type == openborconstant("ATK_NORMAL17"))
{
changeopenborvariant("lasthitc", 0);
}
}
}
// Set hit id on self to attack ID for the next cycle.
changeentityproperty(self, "hitbyid", hit_by_id);
}
Detecting traps might be straightforward but there are couple issues if enemies do detect a trap:
1. What would they do after they found a trap? go back? alter their path? what happens if another trap is found while doing that?
2. What is their priority level if player is nearby a trap? attack despite the trap? stay still?
I was going to suggest using ondoattackscript to cancel damage from traps while changing animation to a dodge trap animation but this might only work against certain traps. BTW the former means enemies don't try to avoid traps at all but instead react to traps.
@ToranksThe solutions all of you propose require incorporating this behavior into all the enemies in the game
hitbyid
before, it's interesting. What this property does exactly? And what's the difference compared with the attackid
localvar?that in an of itself helps , but does not solve the problemthink I'll wait for the version with factions to be released, which will make things a lot easier, to deal with this little problem.
I have no idea, Damon made this code for meWhat this property does exactly? And what's the difference compared with theattackid
localvar?
You can easily turns any npc into static entities using the "nomove" command, same as I'm doing with many decorations.started moving gracefully
name Box_Pieces
type npc
subject_to_wall 0
subject_to_minz 0
subject_to_maxz 0
health 1
lifespan 0.5
nomove 1 1
noquake 1 0
death 1
stealth 2
shadow 0
bounce 1
antigravity -10
onmoveascript data/scripts/updateentity/pieces.c
anim idle
bouncefactor 3
loop 0
delay 2
offset 100 162
frame data/chars/obstacles/box13.png
I will check it, honestly I never tried to make any entity hostile to type "trap".findtarget does not detect traps, even if the enemy is hostile to traps
name St6_Squeezer
type npc
subtype notgrab
hostile player npc
candamage player enemy npc obstacle
nolife 1
nomove 1 1
nodrop 2
shadow 0
stealth 2
offscreenkill 6000
name dan
type enemy
aimove chase
candamage player npc
hostile player npc
[...]
thinkscript data/scripts/traps/chase.c
[...]
anim walk
range 0 300
rangea -200 200
rangez -200 200
void main()
{
void self = getlocalvar("self");
void trap = findtarget(self, openborconstant("ANI_WALK"));
void isfire = getentityproperty(trap, "model");
if(isfire == "potfire" || isfire == "potfire2" || isfire == "potfire3")
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_AVOID"));
}
else
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE"));
}
}
name potfire
type npc
lifespan 120
nolife 1
nomove 1 1
alpha 1
hostile player enemy npc
candamage player enemy npc
Really looks weird like if they are not avoiding properly, try replacing "model" by "defaultname", this is the format I'm currently using.The guy
C++:name dan type enemy aimove chase candamage player npc hostile player npc [...] thinkscript data/scripts/traps/chase.c [...] anim walk range 0 300 rangea -200 200 rangez -200 200
The script
C#:void main() { void self = getlocalvar("self"); void trap = findtarget(self, openborconstant("ANI_WALK")); void isfire = getentityproperty(trap, "model"); if(isfire == "potfire" || isfire == "potfire2" || isfire == "potfire3") { changeentityproperty(self, "aimove", openborconstant("AIMOVE1_AVOID")); } else { changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE")); } }
The fire
C#:name potfire type npc lifespan 120 nolife 1 nomove 1 1 alpha 1 hostile player enemy npc candamage player enemy npc
The result:
This erratic behavior is not entirely satisfactory, nor does it completely prevent them from burning. It requires a better review, although at the moment it's better than before, since they usually walk into the fire like fools as soon as I stand next to (or between) the fire.
void main()
{
void self = getlocalvar("self");
void trap = findtarget(self, openborconstant("ANI_WALK"));
void isfire = getentityproperty(trap, "defaultname");
if(isfire == "potfire" || isfire == "potfire2" || isfire == "potfire3")
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_AVOID"));
}
else
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE"));
}
}
It depends on the usage. As an example, the squeezer I mentioned in the SOR1 route stage 6 needs a more complex behaviour against players, attacking when they approach, but the traps in the SOR3 route stage 8 (the forest) are simple type trap entities that react when touched.@Kratus what is the advantage of having a trap as an npc?
void main()
{
void self = getlocalvar("self");
void trap = findtarget(self, openborconstant("ANI_WALK"));
void isfire = getentityproperty(trap, "defaultname");
if(isfire == "potfire" || isfire == "potfire2" || isfire == "potfire3")
{
void anim = getentityproperty(self, "animationID"); //GET THE CURRENT ANIMATION
int z1 = getentityproperty(self, "z"); //ENEMY
int z2 = getentityproperty(trap, "z"); //NPC TRAP
int limit = 50; //DISTANCE LIMIT BETWEEN BOTH
int range = (z1 - z2 < limit);
if(range && anim != openborconstant("ANI_DODGE")){ //CHECK RANGE AND PREVENT TO REPEATING THE DODGE ANIMATION
changeentityproperty(self, "velocity", NULL(), 2, NULL()); //APPLY Z VELOCITY
changeentityproperty(self, "animation", openborconstant("ANI_DODGE")); //CHANGE ANIMATION
}
}
else
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE"));
}
}
void main()
{
void self = getlocalvar("self");
void trap = findtarget(self);
void isfire = getentityproperty(trap, "defaultname");
if(isfire == "potfire" || isfire == "potfire2" || isfire == "potfire3")
{
void anim = getentityproperty(self, "animationID"); //GET THE CURRENT ANIMATION
int z1 = getentityproperty(self, "z"); //ENEMY
int z2 = getentityproperty(trap, "z"); //NPC TRAP
int x1 = getentityproperty(self, "x"); //ENEMY
int x2 = getentityproperty(trap, "x"); //NPC TRAP
int range = (z1 - z2);
int rangez = (-60 < (z1 - z2) < 60);
int rangex = (-120 < (x1 - x2) < 120);
if(range > 0 && range < 45 && anim != openborconstant("ANI_JUMP")){ //CHECK RANGE AND PREVENT TO REPEATING THE DODGE ANIMATION
changeentityproperty(self, "animation", openborconstant("ANI_JUMP")); //CHANGE ANIMATION
tossentity(self, 2, 0, 2);
}
if(range < 0 && range > -45 && anim != openborconstant("ANI_JUMP")){ //CHECK RANGE AND PREVENT TO REPEATING THE DODGE ANIMATION
changeentityproperty(self, "animation", openborconstant("ANI_JUMP")); //CHANGE ANIMATION
tossentity(self, 2, 0, -2);
}
else if (rangez && rangex) {
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_AVOID"));
}
else
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_NORMAL"));
}
}
else
{
changeentityproperty(self, "aimove", openborconstant("AIMOVE1_CHASE"));
}
}