View Issue Details

IDProjectCategoryView StatusLast Update
0002245The Dark ModAIpublic24.11.2017 16:28
Reportergrayman Assigned To 
PrioritynormalSeveritynormalReproducibilityalways
Status acknowledgedResolutionopen 
PlatformWin32OSWindowsOS VersionXP
Product VersionTDM 1.02 
Summary0002245: AI striking player transfers pain to player's teammate
DescriptionI'm on team 0.

AI "Martin" is on team 2.

AI "Lewis" is on team 0.

Martin attacks me. Lots of pain and red flashes.

Lewis attacks Martin.

Martin doesn't respond to Lewis; he just continues to pound me.

However, the pain that I would normally be receiving is transferred to Lewis, probably because Lewis is registered with Martin as an attacker. I'm receiving no pain and no red flashes. Martin does NOT turn around to battle Lewis, but continues to flail away at me.

Lewis dies.

Martin continues to whack at me. The pain and red returns, and I die.

So the bug here is most likely that Martin did not turn toward Lewis to engage him, though his sword strikes on me are inflicting pain on Lewis.
Steps To ReproduceBuild the attached map "fight.map".

When it starts up, just stand there. Martin is on the left, Lewis on the right.

Martin will come after you, and Lewis will come after Martin.

I lowered Lewis's health so he dies more quickly.
TagsNo tags attached.
Attached Files
fight.map (8,070 bytes)   
Version 2
// entity 0
{
"classname" "worldspawn"
"editor_drLastCameraPos" "-299.727 -60.4772 22.9334"
"editor_drLastCameraAngle" "-29.1 319.5 0"
"editor_drMapPos1" "1738.55 1171.14 -520.531"
"editor_drMapAngle1" "14.7001 87.8977 0"
"editor_drMapPos2" "414.798 255.441 -264.933"
"editor_drMapAngle2" "2.10002 84.5976 0"
"editor_drMapPos3" "-749.97 -1606.21 -470.066"
"editor_drMapAngle3" "-3.29998 6.59757 0"
"editor_drMapPos4" "1014.05 -953.679 -556.857"
"editor_drMapAngle4" "-10.2 355.498 0"
"editor_drMapPos5" "987.599 3513.79 -319.877"
"editor_drMapAngle5" "-61.1999 172.198 0"
"editor_drMapPos6" "-1032.5 -2840 739.5"
"editor_drMapAngle6" "-77.0999 175.798 0"
"editor_drMapPos7" "952.822 285.005 1366.04"
"editor_drMapAngle7" "-74.8 149.373 0"
"editor_drMapPos8" "976 424 320"
"editor_drMapAngle8" "-3 15.3467 0"
"editor_drMapPos9" "409.146 547.464 392.83"
"editor_drMapAngle9" "-16.8 284.947 0"
// primitive 0
{
brushDef3
{
( 0 0 1 -72 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 1 0 -392 ) ( ( 0.0078125 0 255.9375 ) ( 0 0.0078125 255 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 1 0 0 176 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 255 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -184 ) ( ( 0.0078125 0 253.25 ) ( 0 0.0078125 3.40625 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 -120 ) ( ( 0.0078125 0 0.0625 ) ( 0 0.0078125 255 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -376 ) ( ( 0.0078125 0 0.1875 ) ( 0 0.0078125 255 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
// primitive 1
{
brushDef3
{
( 1 0 0 176 ) ( ( 0.0078125 0 254.46875 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -64 ) ( ( 0.0078125 0 254.46875 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 -128 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -376 ) ( ( 0.0078125 0 1.53125 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 1 0 120 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 1 -64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
// primitive 2
{
brushDef3
{
( 0 1 0 -392 ) ( ( 0.01339285714285714 0 1.285714285714286 ) ( 0 0.00390625 0.75 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
( 1 0 0 272 ) ( ( 0.01339285714285714 0 1.392857142857143 ) ( 0 0.00390625 0.75 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
( 0 0 -1 -64 ) ( ( 0.01339285714285714 0 1.392857142857143 ) ( 0 0.00390625 0.71875 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
( 0 -1 0 96 ) ( ( 0.01339285714285714 0 1.392857142857143 ) ( 0 0.00390625 0.75 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
( -1 0 0 -280 ) ( ( 0.01339285714285714 0 1.392857142857143 ) ( 0 0.00390625 0.75 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
( 0 0 1 -64 ) ( ( 0.01339285714285714 0 1.392857142857143 ) ( 0 0.00390625 0.78125 ) ) "textures/darkmod/wood/boards/pier_platform" 0 0 0
}
}
// primitive 3
{
brushDef3
{
( 0 1 0 -392 ) ( ( 0.0078125 0 3.5625 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -64 ) ( ( 0.0078125 0 255 ) ( 0 0.0078125 3.5625 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -384 ) ( ( 0.0078125 0 1 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 1 0 0 376 ) ( ( 0.0078125 0 255 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 -120 ) ( ( 0.0078125 0 252.5 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 1 -64 ) ( ( 0.0078125 0 255 ) ( 0 0.0078125 252.4375 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
// primitive 4
{
brushDef3
{
( 0 1 0 -392 ) ( ( 0.0078125 0 255.9375 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 1 0 0 176 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -72 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -376 ) ( ( 0.0078125 0 0.125 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 1 64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 -120 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
// primitive 5
{
brushDef3
{
( 0 1 0 -392 ) ( ( 0.0078125 0 255.96875 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 1 0 0 168 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 255.96875 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -176 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 -120 ) ( ( 0.0078125 0 0.03125 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 1 -64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0.03125 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
// primitive 6
{
brushDef3
{
( 0 0 1 -64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 1 0 -400 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 1 0 0 176 ) ( ( 0.0078125 0 0.03125 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 0 -1 -64 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( 0 -1 0 392 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
( -1 0 0 -376 ) ( ( 0.0078125 0 0 ) ( 0 0.0078125 0 ) ) "textures/darkmod/stone/brick/bricks_mossy01" 0 0 0
}
}
}
// entity 1
{
"classname" "atdm:ai_citywatch"
"name" "Martin"
"health" "1000"
"origin" "-360 344 -64"
"target" "path_corner_3"
}
// entity 2
{
"classname" "info_player_start"
"name" "info_player_start_1"
"angle" "90"
"health" "1000"
"origin" "-272 -96 -56"
}
// entity 3
{
"classname" "light"
"name" "light_5"
"_color" "0.50 0.50 0.50"
"light_center" "0 0 0"
"light_radius" "320 320 320"
"nodiffuse" "0"
"noshadows" "0"
"nospecular" "0"
"origin" "-264 -16 40"
"parallel" "0"
}
// entity 4
{
"classname" "atdm:ai_citywatch"
"name" "Lewis"
"health" "80"
"origin" "-240 192 -64"
"skin" "citywatch/default_ragged_nopauldrons"
"target" "path_corner_1"
"team" "0"
}
// entity 5
{
"classname" "path_corner"
"name" "path_corner_1"
"origin" "-216 192 -56"
"target" "path_wait_1"
}
// entity 6
{
"classname" "path_wait"
"name" "path_wait_1"
"angle" "-90"
"origin" "-216 152 -16"
"wait" "60"
}
// entity 7
{
"classname" "path_wait"
"name" "path_wait_3"
"angle" "270"
"origin" "-320 304 -16"
"wait" "60"
}
// entity 8
{
"classname" "path_corner"
"name" "path_corner_3"
"origin" "-320 344 -56"
"target" "path_wait_3"
}
// entity 9
{
"classname" "light"
"name" "light_3"
"_color" "0.50 0.50 0.50"
"light_center" "0 0 0"
"light_radius" "320 320 320"
"nodiffuse" "0"
"noshadows" "0"
"nospecular" "0"
"origin" "-208 368 40"
"parallel" "0"
}
// entity 10
{
"classname" "light"
"name" "ambient_world2"
"_color" "0.04 0.04 0.04"
"light_center" "0 0 0"
"light_radius" "7777 7777 7777"
"nodiffuse" "0"
"noshadows" "0"
"nospecular" "0"
"origin" "-336 239.5 15.5"
"parallel" "0"
"texture" "lights/ambientlightnfo"
}
// entity 11
{
"classname" "light"
"name" "light_4"
"_color" "0.50 0.50 0.50"
"light_center" "0 0 0"
"light_radius" "320 320 320"
"nodiffuse" "0"
"noshadows" "0"
"nospecular" "0"
"origin" "-352 368 40"
"parallel" "0"
}
fight.map (8,070 bytes)   

Relationships

related to 0002925 resolvedgrayman AI should look at target when warning 
related to 0003331 resolvedgrayman AI have several problems when entering Combat 

Activities

Ishtvan

Ishtvan

25.10.2010 03:07

reporter   ~0003267

Last edited: 25.10.2010 03:09

I suspect what is happening isn't really "pain transferring" or even strictly a bug: The AI is swinging its sword at you, but hitting the other AI because they got in the way. Collision check is done against all enemies of the attacker, so it's possible to swing a sword with the intention of hitting one enemy, but actually end up hitting another. You can make this mistake too as the player, if another enemy is standing too close to the one you're hitting.

Don't know of an easy fix for this one. We could track whether it happens in the AI combat subtask, and maybe tell them to use a different attack than the one they last used that hit the wrong person.

EDIT: One way to test this would be to turn on melee clipmodel visualization (tdm_melee_debug 1), and stand somewhere on the other side of the friendly AI so that hopefully the enemy's sword attacks can hit you without hitting them. The clipmodels of the enemy attacks are rather large though, they might even hit people slightly behind them first.

grayman

grayman

25.10.2010 03:30

viewer   ~0003269

Hmmm. So what's happening is that the sword is swinging back, hits the AI at the rear, then swings forward to hit the player.

This makes sense, except the player appears to take no damage. Maybe the sword swinging animation only gives pain to the first entity it hits, not all entities it hits.

It's also possible that the pain-dealing AI thinks he's facing the guy in the rear. The pain is handed out correctly, but for some reason he wasn't able to turn around.

I'll see if I can figure out where all the pain is supposed to be going, and where it really is going. If it makes sense as is, I'll close this out as not a problem.

Thanks for this insight. It hadn't occurred to me.
Ishtvan

Ishtvan

25.10.2010 03:39

reporter   ~0003270

Last edited: 25.10.2010 03:40

Yeah, by design, the swords can only hit one person per attack. It wouldn't be too realistic for the sword to cleave through or stab through one person and hit another. We were hoping that in the future, there would be some sort of bounce back or recovery animation so that you can clearly see the sword has hit something and stopped the swing. For now it just plays through the whole animation, which can cause confusion in cases like this.

It doesn't start testing for collisions until it swings forward, so they wouldn't be getting hit on the backswing, technically. But if an AI is really close behind, the larger CM of the AI's attacks might end up hitting them in the first frame of the forward swing. We can't really make the CMs smaller though, as that would expose some spots the player could stand to never get hit. They've been tweaked pretty extensively already.

grayman

grayman

25.10.2010 04:12

viewer   ~0003271

I've verified that this is the sequence:

Enemy hits me.
Friend hits enemy.
Enemy and friend duke it out until friend dies.
Enemy hits me enough times to kill me.

All of this happens while the enemy is facing me, so it looks like I'm getting hit with each of his swings.

I think it would be easiest to make the enemy ignore the friend while the enemy cuts me down. Probably a simple change to only allow the hit if the AI being hit is not "behind" the attacker. If not allowed, the swing would next encounter me, and that hit would be allowed.

The more difficult change would be to make the enemy turn back toward the friend before continuing his attack, then turn back to me when he's done.

Does the easier solution sound reasonable?
Ishtvan

Ishtvan

25.10.2010 04:24

reporter   ~0003272

Last edited: 25.10.2010 04:26

I don't think the first change would be very simple. First you would need to detect the situation, but hitting things happens at the basic melee physics level, where you'd have to add a lot of code to see what AI am I attached to, who is attacking them, who are they trying to attack, etc. Once you detected the situation, you would have to build up some sort of ignore list and teleport things in that list away temporarily while the trace is going on. A trace function can only take one ignore parameter, that's why you need this hack of temporarily teleporting things away, then putting them back.

I'm also not sure about that change, because physically you would expect that an AI standing in the way of the enemy's sword would get hit. The AI just isn't smart enough to realize that. I'd rather see the change made at the AI level rather than complicate the physics a lot to make the sword teleport through things, which might even appear wrong from the player's perspective.

For example, if the AI is taking damage form another enemy and not the one they've decided to attack, maybe turn and face the other enemy. If the AI still wants to hit you and their attacks are hitting another AI, have them check what side they're on and rule out the attack that covers that side (for example, they hit an AI on their left trying to get at you, have them stop doing left to right slashes). They already know who they're trying to attack and who they hit, so that might not be _that_ hard to implement.

I'm not sure if it's a very high priority, though. How often does this happen? EDIT: It used to happen that they'd hit their teammates this way, but we made the sword pass through their teammates as a quick fix, because it is a bit complicated to try to give them some spatial reasoning so they can use attacks that avoid one AI and hit another.

grayman

grayman

25.10.2010 12:21

viewer   ~0003273

Found this in the code:

"// TODO: Figure out how to switch enemies to face & parry a new one"

So that's the right thing to do.

Issue History

Date Modified Username Field Change
07.06.2010 13:07 grayman New Issue
07.06.2010 13:07 grayman File Added: fight.map
10.06.2010 17:35 greebo Status new => acknowledged
30.09.2010 19:23 tels Target Version => TDM 1.03
25.10.2010 03:07 Ishtvan Note Added: 0003267
25.10.2010 03:09 Ishtvan Note Edited: 0003267
25.10.2010 03:30 grayman Note Added: 0003269
25.10.2010 03:30 grayman Assigned To => grayman
25.10.2010 03:39 Ishtvan Note Added: 0003270
25.10.2010 03:40 Ishtvan Note Edited: 0003270
25.10.2010 03:40 Ishtvan Note Edited: 0003270
25.10.2010 04:12 grayman Note Added: 0003271
25.10.2010 04:24 Ishtvan Note Added: 0003272
25.10.2010 04:24 Ishtvan Note Edited: 0003272
25.10.2010 04:26 Ishtvan Note Edited: 0003272
25.10.2010 12:16 greebo Target Version TDM 1.03 =>
25.10.2010 12:21 grayman Note Added: 0003273
10.10.2017 21:30 nbohr1more Relationship added related to 0002925
10.10.2017 21:37 nbohr1more Relationship added related to 0003331
24.11.2017 16:28 grayman Assigned To grayman =>