• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Solved] Protect Items

Status
Not open for further replies.
Level 17
Joined
Feb 11, 2011
Messages
1,860
Hi guys,

I would like a system to put in my map that prevents other players from picking up and attacking your items. I have a trigger that sets the item's owner when it is bought:

  • Item Ownership
    • Events
      • Unit - A unit Sells an item (from shop)
    • Conditions
    • Actions
      • Item - Change ownership of (Sold Item) to (Owner of (Buying unit)) and Retain color
However, I'm not sure about other triggers/scripts to use to stop the items from being attacked and picked up by other players.

Thanks for any help!
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
I would save the Item Handle into the player number.
Hashtable - Save Key(ItemId) as 0 of (Player Number) in ItemHash
And (event) if a unit is given an ordered targeting an object , and (condition) the object is an item, check the Item ID in the ItemHash. If the item handle isn't saved into the Owner of Triggering Unit number in the ItemHash, means he hasn't picked that item. Order the unit to stop, and display a message if you want.

I think that the Ownership already disables picking by other players... If doesn't, you can use the same ItemId in the hash.

A unit acquires an item
-> Check the item Id in the hash.



I've thinking a bit about this. If you find problems doing it this way, you can invert the system, meaning that you don't save the itemId into player number, but save player number into ItemId.
 
Level 11
Joined
Sep 14, 2009
Messages
284
You could use custom values and set the custom value to the player number the first time a player obtains an item, then make it so if the number don't match make the hero drop the item.
Basically; All items have custom value 0 from the start, which can be picked up by all players.
Make a trigger that if the custom value is not equal to 0 or not equal to player number of owner of hero manipulating item then make unit drop the item.

As for the attacking part, just make a trigger that when a unit is issued an order to attack an item order unit to stop or move to the item instead.
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
There. This work, is easy, MUI, leakless and doesn't require JNPG. I forgot items had Custom Values, that why I talked aboud Hashtables before :)

  • Item Owning
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Set ItemVar = (Item being manipulated)
      • Set CusVal = (Custom value of ItemVar)
      • Set PlaNum = (Player number of (Triggering player))
      • Set Force = (Player group((Triggering player)))
      • Custom script: if udg_CusVal == 0 then
      • Item - Set the custom value of ItemVar to PlaNum
      • Game - Display to Force the text: |cffff00ffNow you own this item|r
      • Custom script: elseif udg_CusVal != udg_PlaNum then
      • Hero - Drop ItemVar from (Triggering unit)
      • Game - Display to Force the text: |cffff0000This item doesn't belong to you|r
      • Custom script: endif
      • Custom script: call DestroyForce(udg_Force)
If you don't want to display the messages, you can delete these

  • Set Force = (Player group((Triggering player)))
  • Game - Display to Force the text: |cffff00ffNow you own this item|r
  • Game - Display to Force the text: |cffff0000This item doesn't belong to you|r
  • Custom script: call DestroyForce(udg_Force)
The custom scripts Custom script: if udg_CusVal == 0 then and Custom script: elseif udg_CusVal != udg_PlaNum then are just becase I don't like having all those GUI lines for If/Then/Else. This way looks cleaner, and it's slightly faster. It's the same than If/Then/Else but a bit improved.

EDIT: Forgot the attack thing. With this you avoid others from attacking other players items.
  • PreventItemAttack
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(attack))
      • (Custom value of (Target item of issued order)) Not equal to (Player number of (Triggering player))
    • Actions
      • Unit - Order (Triggering unit) to Move To (Target item of issued order)
      • Set Force = (Player group((Triggering player)))
      • Game - Display to Force the text: |cffff0000You can't...
      • Custom script: call DestroyForce(udg_Force)
You can remove the last 3 actions if you don't want to display the message. Somehow, if you use "Order unit to Stop" it goes and attacks/picks the item... This way it just moves to it, but doesn't picks it not attacks it.

I guess you excluded Items from being targeted by spells... =) I'm not sure if "attack-ground" would damage items.

Enjoy!
 

Attachments

  • ItemOwning.w3x
    13.5 KB · Views: 72
Level 17
Joined
Feb 11, 2011
Messages
1,860
Awesome, thanks so much man! Don't worry, I do understand what you are doing because I know JASS. Thanks again!

  • PreventItemAttack
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(attack))
      • (Custom value of (Target item of issued order)) Not equal to (Player number of (Triggering player))
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Target unit of issued order) Not equal to (Picked unit)
            • Then - Actions
              • Unit - Order (Triggering unit) to Move To (Target item of issued order)
              • Set Force = (Player group((Triggering player)))
              • Game - Display to Force the text: |cffff0000You can't...
              • Custom script: call DestroyForce(udg_Force)
            • Else - Actions
              • Set Force = (Player group((Triggering player)))
              • Game - Display to Force the text: You targeted a unit.
              • Custom script: call DestroyForce(udg_Force)
When I modify your trigger like this, it triggers BOTH the Then - Actions and Else - Actions when I attack another UNIT. How is this possible?!
 
Last edited:
Level 17
Joined
Feb 11, 2011
Messages
1,860
Update: There is one problem with your "PreventItemAttack" trigger. When I place 2 heroes and make them attack each other, it says "You can't pick nor attack items that doesn't belong to you". How can I fix this?

Is there a way to check whether the targeted object is an item?
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
The thing is... Units / Items / Destructibles are Widgets = Objects.

Edit: This worked for me. Sadly, you can check more things about Units and Destructibles than you can with Items, which have only 5 comparisons. Instead of excluding "What your target is" you are forced to exclude "Everything your target isn't".

  • PreventItemAttack
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(attack))
      • ((Target unit of issued order) is alive) Equal to False
      • ((Target destructible of issued order) is alive) Equal to False
      • (Custom value of (Target item of issued order)) Not equal to (Player number of (Triggering player))
    • Actions
      • Set Point = (Position of (Triggering unit))
      • Unit - Order (Triggering unit) to Move To Point
      • Custom script: call RemoveLocation(udg_Point)
      • Set Force = (Player group((Triggering player)))
      • Game - Display to Force the text: |cffff0000You can't...
      • Custom script: call DestroyForce(udg_Force)
It allows freely attacking units and destructibles. You don't need to do do the "Pick Every unit..." you showed in the last post.

As you can see, I changed the "Order Unit to Move to the Item" for "Move Unit to Point". It stops the unit current action (attack the item) more efficiently than ordering to stop (which ironically doesn't stops the unit).
 
Last edited:
Level 17
Joined
Feb 11, 2011
Messages
1,860
JASS:
function Protect_Items takes nothing returns boolean
    local real x = GetItemX(GetOrderTargetItem())
    local real y = GetItemY(GetOrderTargetItem())
    if (GetItemUserData(GetOrderTargetItem()) != GetConvertedPlayerId(GetTriggerPlayer())) and (IsUnitAliveBJ(GetSpellTargetUnit()) == false) and (IsDestructableAliveBJ(GetSpellTargetDestructable()) == false) then
        call IssuePointOrder(GetTriggerUnit(), "move", x, y)
    else
        call BJDebugMsg("Target was owned/was unit/was destructable.")
    endif
    return false
endfunction

function InitTrig_Protect_Items takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
    call TriggerAddCondition(t, Condition(function Protect_Items))
    set t = null
endfunction

With this, if I order a unit to attack a unit, the attacker moves to the center of the map instead of attacking normally (it can't get the co-ordinates of the targeted item so it uses the center of the map). Any suggestions?
 
You can replace GetSpellTargetUnit() and GetSpellTargetDestructable() with GetOrderTargetUnit() and GetOrderTargetDestructable(). However, if I were you, I'd do it like this:
JASS:
function Protect_Items takes nothing returns boolean
    if GetOrderTargetItem() == null then
        // this condition will return true if the target was not an item
        // if the item targeted is null (aka: not an item) then it will skip remaining actions
        call BJDebugMsg("Target owned was a unit/destructable.")
        return false
    endif
    if GetItemUserData(GetOrderTargetItem()) != (GetPlayerId(GetTriggerPlayer()) + 1) then
    // GetConvertedPlayerId(p) is actually just (GetPlayerId(p) + 1)
        call IssuePointOrder(GetTriggerUnit(), "move", GetItemX(GetOrderTargetItem()), GetItemY(GetOrderTargetItem()))
        // you only use x and y once, so you don't have to put them as locals
    endif
    return false
endfunction

function InitTrig_Protect_Items takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
    call TriggerAddCondition(t, Condition(function Protect_Items))
    set t = null
endfunction

=)
 
Status
Not open for further replies.
Top