Jump to content

[SA CLEO] Detect that the char is trying to attack another char.


DavidReyes2250

Recommended Posts

DavidReyes2250

The thing about the title.

Try "get_char_kill_target_char 0@ store to 1@" but it doesn't seem to work as a conditional to detect if the char tries to attack another char (possible CLEO+ bug?)

 

if
get_char_kill_target_char 0@ store_to 1@  // Char 0@ target to kill char 1@

 

Link to comment
Share on other sites

Hm... That's one of the opcodes on my list to document in the Sanny Builder Library. I could repeat your tests; do you have a small test script?

 

The format you are using requires sa_scr mode; double check in the bottom right.

 

Have you tried finding the kill target the hard way, chasing down pointers and whatnot to confirm the incorrect results?

 

According the the source code, get_char_kill_target_char is a conditional command, so you're using it correctly.

 

How did you set up your test: identify each character, and determine their tasks?

Edited by OrionSR
Link to comment
Share on other sites

DavidReyes2250
{$CLEO .cs}
{$USE CLEO+}

script_name 'test'

:noname1
model.Load(#BALLAS1)
038b:load_requested_models

:noname_1
wait 0
if
model.Available(#BALLAS1)
jf @noname_1
actor.StorePos($PLAYER_ACTOR, 0@, 1@, 2@)
actor.Create(3@, pedtype.Mission1, #BALLAS1, 0@, 1@, 2@)
actor.SetImmunities(3@, 1, 1, 1, 1, 1)
077A: set_actor 3@ acquaintance 4 to_actors_pedtype 0 // see ped.dat
077A: set_actor 3@ acquaintance 4 to_actors_pedtype 4 // see ped.dat
timera = 0

:NONAME_2
wait 0
if
TIMERA > 10000
jf @NONAME_3
if
actor.Dead(3@)
jf @NONAME_2
terminate_this_custom_script

:NONAME_3
if
get_char_kill_target_char 3@ store_to 4@
jf @noname_5
actor.StorePos(4@, 5@, 6@, 7@)
020C: create_explosion_with_radius 0 at 5@ 6@ 7@

:noname_5
timera = 0
jump @NONAME_2

In this quick test, imagine that a Balla is hostile towards the player and male pedestrians.
When a certain time passes, if the Balla is trying to kill someone, the code takes the actor that the Balla is trying to kill, and in the position of the actor to be killed, there will be an explosion and the process will restart. (What I have in mind to do)

 

The problem is that if the Balla is not attacking anyone (neither the player nor a pedestrian), the code takes the last actor that the Balla wanted to kill previously and there will be an explosion, which I think should not happen.

Edited by DavidReyes2250
Link to comment
Share on other sites

Huh, maybe the Balla is exploding before he attacks anyone, but has gone hostile.
Where kill target is the main task, there will be various simple task, like run towards the target, or use weapon.

 

I put together a small test script; everything seems to be working properly. I'll check out yours.

This one is for sa_scr mode. It doesn't make a difference for the cleo+ opcode but I'm pretty sure other used opcodes have their params swapped.

Spoiler
{$CLEO .cs}
{$USE CLEO+}
{edit mode = sa_scr}

int bill, kill, target
int bill_blip, kill_blip
int x,y,z

script_name 'killbil'
wait 5000

GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS $player_actor 1.0 3.0 1.0 x y z
CREATE_RANDOM_CHAR x y z bill
ADD_BLIP_FOR_CHAR bill bill_blip
CHANGE_BLIP_COLOUR bill_blip 1
wait 0

GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS $player_actor -1.0 -3.0 1.0 x y z
CREATE_RANDOM_CHAR x y z kill
ADD_BLIP_FOR_CHAR kill kill_blip
set_char_relationship kill 4 4
wait 0

//TASK_KILL_CHAR_ON_FOOT kill bill // $player_actor

while true
  wait 0
  if
    GET_CHAR_KILL_TARGET_CHAR kill store_to target
  then
    if
      bill == target
    then
      0ace: "Bill is the target"
    else
      0ace: "Bill is not the target"
    end
  else
    0ace: "Target not found"
  end
wait 4000
end

wait 10000
TERMINATE_THIS_CUSTOM_SCRIPT

 

 

Link to comment
Share on other sites

47 minutes ago, DavidReyes2250 said:

The problem is that if the Balla is not attacking anyone (neither the player nor a male pedestrian), the Balla will still explode, which I think should not happen.

Wow. That guy is ominous. RUN AWAY! I needed a small wait to avoid being instantly killed.

But I think I see what you mean. Eventually he runs out of targets, and was running in circles with no particular target.

 

I think the problem may be that his kill target doesn't clear when the task is done. It might remain as garbage, waiting for the next target.

Link to comment
Share on other sites

DavidReyes2250
29 minutes ago, OrionSR said:

Wow. That guy is ominous. RUN AWAY! I needed a small wait to avoid being instantly killed.

But I think I see what you mean. Eventually he runs out of targets, and was running in circles with no particular target.

 

I think the problem may be that his kill target doesn't clear when the task is done. It might remain as garbage, waiting for the next target.

Mine error!!

 

:NONAME_2
wait 0
if
not TIMERA > 10000
jf @NONAME_3
if
actor.Dead(3@)
jf @NONAME_2
terminate_this_custom_script

is "not TIMERA > 10000", sorry

But the situation remains the same.

 

I think CLEO+ does not forget the last actor that Balla tried to kill and still takes him into account (possible bug?)
And even if it's not a bug, any alternative?

Edited by DavidReyes2250
Link to comment
Share on other sites

31 minutes ago, DavidReyes2250 said:

I think it's a CLEO+ bug.

I disagree. I think the command is correctly reading the data as it exists in the character's data. It is normal for the game to leave old data. It's up to you to figure out another detection strategy. Like, only check the kill target if a kill task is active. Sorry, I don't have much experience with tasks. 

 

 

Edited by OrionSR
Link to comment
Share on other sites

1 hour ago, DavidReyes2250 said:

Mine error!!

Just wanted you to know that getting chased down the alley and around the block by a continuously exploding balla bomber was very entertaining. I'm still thinking about it. There's bound to be a good puzzle mission that exploits that mechanic.

Link to comment
Share on other sites

On 9/26/2023 at 2:37 AM, DavidReyes2250 said:

The thing about the title.

 

I did it like that in my script. A bodyguard 11@ will attack anyone who damaged the player.

0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
15@ += 0x764 //attacker offset               
0A8D: 15@ = read_memory 15@ size 4 virtual_protect 0 //struct of attacker 
if 15@ >1 //check if there is an attacker
then
    0D4E: 19@ = struct 15@ offset 0x36 size 4 //forgot what it is )) i think it's something flag related, to get type of attack
        if
            19@ == 35
//          19@ == 26 //hit by car
        then
            0AEA: 26@ = ped_struct 15@ handle //attacker handle - for cleo commands we now use @26
            if and
                8118: not actor 26@ dead
                30@ == 0 //flag check if kill_actor order was already given - this is must have to remove continous kill_actor command
						 //that would result in stuttering
            then
                if       
                    8118: not actor 11@ dead //check if bodyguard is alive
                then
                    30@ = 1 //set flag that kill_actor was given
                    05E2: AS_actor 11@ kill_actor 26@ //11@ is the bodyguard
                end
            end
        end
end

    if and //check if attacker is killed and kill_actor command was given
        0118: actor 26@ dead
        30@ == 1
    then
        0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
        15@ += 0x764 //attacker offset     
        0A8C: write_memory 15@ size 4 value 0 virtual_protect 0 //clear info that there was an attacker
        01C2: remove_references_to_actor 26@
        30@ = 0 //reset kill_actor flag
    end
//of course - this should be run in a loop

Downside of this code is that a ped will be considered an attacker only if he reduced player's health. Like, if he starts beating the player and the player will be blocking his punches - it won't count as an attack.


The whole code (part of it - the main loop without creation and end) with 4 bodyguards and ability to give them an order to
kill a ped.
 

Spoiler

 

:Begin
wait 0
if
    8118: not actor 11@ dead
then
    if
        80F2:   not actor 11@ near_actor $PLAYER_ACTOR radius 150.0 150.0 sphere 0
    then
        jump @End
    end        
end
if
    8118: not actor 12@ dead
then
    if
        80F2:   not actor 12@ near_actor $PLAYER_ACTOR radius 150.0 150.0 sphere 0
    then
        jump @End
    end        
end
if
    8118: not actor 13@ dead
then
    if
        80F2:   not actor 13@ near_actor $PLAYER_ACTOR radius 150.0 150.0 sphere 0
    then
        jump @End
    end        
end
if
    8118: not actor 14@ dead
then
    if
        80F2:   not actor 14@ near_actor $PLAYER_ACTOR radius 150.0 150.0 sphere 0
    then
        jump @End
    end        
end
if and
0118: actor 11@ dead
0118: actor 12@ dead
0118: actor 13@ dead
0118: actor 14@ dead
then
jump @End
end
0256:   player $PLAYER_CHAR defined
jf @End

0A96: 20@ = ped $PLAYER_ACTOR struct
0D4E: 20@ = struct 20@ offset 0x79C size 4
if and
20@ >0
0AB0:   key_pressed 192 //`
then
  0AEA: 26@ = ped_struct 20@ handle
  089F: get_actor 26@ pedtype_to 27@
    if and
        27@ <> 8       
        8118: not actor 11@ dead
    then
        05E2: AS_actor 11@ kill_actor 26@
    end
    if and
        27@ <> 8       
        8118: not actor 12@ dead
    then
        05E2: AS_actor 12@ kill_actor 26@
    end
    if and
        27@ <> 8       
        8118: not actor 13@ dead
    then
        05E2: AS_actor 13@ kill_actor 26@
    end
    if and
        27@ <> 8       
        8118: not actor 14@ dead
    then
        05E2: AS_actor 14@ kill_actor 26@
    end
end

0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
15@ += 0x764 //attacker offset               
0A8D: 15@ = read_memory 15@ size 4 virtual_protect 0 //struct of attacker 
if 15@ >1 
then
    0D4E: 19@ = struct 15@ offset 0x36 size 4
        if
            19@ == 35
//          19@ == 26 //hit by car
        then
            0AEA: 26@ = ped_struct 15@ handle //attacker handle
            if and
                8118: not actor 26@ dead
                30@ == 0
            then
                if       
                    8118: not actor 11@ dead
                then
                    30@ = 1
                    05E2: AS_actor 11@ kill_actor 26@
                end
                if       
                    8118: not actor 12@ dead
                then
                    30@ = 1
                    05E2: AS_actor 12@ kill_actor 26@
                end
                if       
                    8118: not actor 13@ dead
                then
                    30@ = 1
                    05E2: AS_actor 13@ kill_actor 26@
                end
                if       
                    8118: not actor 14@ dead
                then
                    30@ = 1
                    05E2: AS_actor 14@ kill_actor 26@
                end
            end
        end
end

    if and
        0118: actor 26@ dead
        30@ == 1
    then
        0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
        15@ += 0x764 //attacker offset     
        0A8C: write_memory 15@ size 4 value 0 virtual_protect 0
        01C2: remove_references_to_actor 26@        
        30@ = 0
    end

jump @Begin

 

Edited by vladvo
  • Like 3
Link to comment
Share on other sites

DavidReyes2250
On 9/27/2023 at 5:14 AM, vladvo said:

I did it like that in my script. A bodyguard 11@ will attack anyone who damaged the player.

0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
15@ += 0x764 //attacker offset               
0A8D: 15@ = read_memory 15@ size 4 virtual_protect 0 //struct of attacker 
if 15@ >1 //check if there is an attacker
then
    0D4E: 19@ = struct 15@ offset 0x36 size 4 //forgot what it is )) i think it's something flag related, to get type of attack
        if
            19@ == 35
//          19@ == 26 //hit by car
        then
            0AEA: 26@ = ped_struct 15@ handle //attacker handle - for cleo commands we now use @26
            if and
                8118: not actor 26@ dead
                30@ == 0 //flag check if kill_actor order was already given - this is must have to remove continous kill_actor command
						 //that would result in stuttering
            then
                if       
                    8118: not actor 11@ dead //check if bodyguard is alive
                then
                    30@ = 1 //set flag that kill_actor was given
                    05E2: AS_actor 11@ kill_actor 26@ //11@ is the bodyguard
                end
            end
        end
end

    if and //check if attacker is killed and kill_actor command was given
        0118: actor 26@ dead
        30@ == 1
    then
        0A96: 15@ = ped $PLAYER_ACTOR struct //ped struct
        15@ += 0x764 //attacker offset     
        0A8C: write_memory 15@ size 4 value 0 virtual_protect 0 //clear info that there was an attacker
        01C2: remove_references_to_actor 26@
        30@ = 0 //reset kill_actor flag
    end
//of course - this should be run in a loop

 

Your code seems like a good solution to me, but...

 

And if instead of getting the offset of the attacker, it's better to get the offset of the ped that is going to attack, which is what I'm looking for the most, something like:

0A96: POINTER = ped KILLER struct
POINTER += ????  // offset of the ped that wants to attack
0AEA: VICTIM = ped_struct POINTER handle
Edited by DavidReyes2250
Link to comment
Share on other sites

And if instead of getting the offset of the attacker, it's better to get the offset of the ped that is going to attack, which is what I'm looking for the most, something like:

0A96: POINTER = ped KILLER struct
POINTER += ????  // offset of the ped that wants to attack
0AEA: VICTIM = ped_struct POINTER handle

idk if this you want

 

0EFF: get_char_simplest_active_task 0@ id_to 10@ pointer_to 13@ //not tested but maybe 0AEA: 13@ = actor_struct 13@ handle will work

 

attacker with weapon is 1020

attacker with melee is 1019

victim is 1008 

 

 

{$Cleo}
0000:
0ADF: add_dynamic_GXT_entry "abta1" text "~r~Want to attack or attacking with melee"
0ADF: add_dynamic_GXT_entry "abta2" text "~r~Want to attack or attacking with weapon"
0ADF: add_dynamic_GXT_entry "abta3" text "~y~Victim getting hit"
while true
wait  0
repeat
if    056D: ped 0@ defined
jf    continue
0EFF: get_char_simplest_active_task 0@ id_to 10@ pointer_to 13@ //not tested but maybe 0AEA: 13@ = actor_struct 13@ handle will work
if    10@ == 1019
then  call  @txt 2 ped 0@ gxt 1
end
if    10@ == 1020
then  call  @txt 2 ped 0@ gxt 2
end
if    10@ == 1008
then  call  @txt 2 ped 0@ gxt 3
end
until if 8AE1: 0@ = random_ped_near_point 0.0 0.0 0.0 in_radius 6000.0 find_next 1 pass_deads 1 //IF and SET
end

:txt
0AD3: string 20@v format "abta%d" 1@
00A0: store_ped 0@ position_to 1@ 2@ 3@
0E3F: convert_3d_to_screen_2d 1@ 2@ 3@ checkNearClip 0 checkFarClip 0 store_2d_to 6@ 7@ size_to 8@ 9@
03F0: enable_text_draw 1
0342: enable_text_draw_centered 1
033F: set_text_draw_letter_size 8@ 9@
033E: set_draw_text_position 6@ 7@ GXT 20@v  // Push
ret 0

 

Link to comment
Share on other sites

17 hours ago, DavidReyes2250 said:

it's better to get the offset of the ped that is going to attack, which is what I'm looking for the most, something like:

I have some parts I was making for my script (big thanks to Jack - most of the code is made by him). Maybe you can make something out of it.

0AB1: cleo_call @getCharSimpleActiveTask params 1 param 10@ store_to 0@
//  _ZNK12CTaskManager21GetSimplestActiveTaskEv = 0x6819D0    
:getCharSimpleActiveTask
0A96: 1@ = ped 0@ struct
1@ += 0x47C
0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CPedIntelligence *pedIntel = playa->m_pIntelligence;
1@ += 4 //  CTaskManager * taskManager = pedIntel->m_TaskMgr;  
//  ped->m_pIntelligence->m_TaskMgr.GetSimplestActiveTask();
0AA8: call_method_return 0x6819D0 struct 1@ num_params 0 pop 0 store_to 1@ 
if 1@ <> 0
then
    1@ += 0
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CTaskVtable
    1@ += 0x10  //  GetID();  
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CTaskVtable->GetID();
    //  ped->m_pIntelligence->m_TaskMgr.GetSimplestActiveTask()->GetID();
    0AA8: call_method_return 1@ struct 1@ num_params 0 pop 0 store_to 1@
end
0AB2: cleo_return 1 1@

//_ZNK12CTaskManager13GetActiveTaskEv = 0x681720
:getCharActiveTask
0A96: 1@ = ped 0@ struct
1@ += 0x47C
0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CPedIntelligence *pedIntel = playa->m_pIntelligence;
1@ += 4 //  CTaskManager * taskManager = pedIntel->m_TaskMgr;
//  ped->m_pIntelligence->m_TaskMgr.GetActiveTask();
0AA8: call_method_return 0x681720 struct 1@ num_params 0 pop 0 store_to 1@ 
if 1@ <> 0
then
    1@ += 0
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CTaskVtable
    1@ += 0x10  //  GetID();  
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  //  CTaskVtable->GetID();
//    //  ped->m_pIntelligence->m_TaskMgr.GetActiveTask()->GetID(); 
   0AA8: call_method_return 1@ struct 1@ num_params 0 pop 0 store_to 1@
//end
0AB2: cleo_return 1 1@

:getCharTask
0A96: 1@ = ped 0@ struct
1@ += 0x47C
0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
1@ += 0x18
0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
if 1@ <> 0
then
    1@ += 0
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
    1@ += 0x10   
    0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0  
    0AA7: call_function_return 1@ num_params 0 pop 0 1@
end
0AB2: cleo_return 1 1@

//if or
//0@ == 1019 //TASK_SIMPLE_FIGHT_CTRL
//0@ == 1020 //TASK_SIMPLE_GUN_CTRL	
//then
//jump @FIGHT_LOOP
//end

 

Link to comment
Share on other sites

who want long script here its 

 

0EFF: get_char_simplest_active_task 0@ id_to 10@ pointer_to 13@ //not tested but maybe 0AEA: 13@ = actor_struct 13@ handle will work

Link to comment
Share on other sites

49 minutes ago, Strs said:

//not tested but maybe 0AEA: 13@ = actor_struct 13@ handle will work

I don't think so, but again untested. According to various references, I'm expecting that the character's handle should be passed to 0EFF, not the struct. I've documented it as such in the Sanny Builder Library, so if I'm wrong I'd like to know so I can fix it.
https://sannybuilder.com/lib/sa/CLEO+/0EFF

 

Also, SBL has an enum for the TaskIDs, which should help clarify the returned values.
https://library.sannybuilder.com/#/sa/enums/TaskId

 

Edited by OrionSR
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 1 User Currently Viewing
    0 members, 0 Anonymous, 1 Guest

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.