Page 3 of 3 FirstFirst 1 2 3
Results 21 to 29 of 29

Thread: Simple questions, Simple answers

  1. #21
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,866
    For those of you that worked with GetEstimatedDamageToTarget(), can you please explain these differences in output, please? So, I am trying to teach my bots to lane and working with some code draft for LH-ing. Upon coding it, I wanted to output some calls just to see how I can use the GetEstimatedDamageToTarget() function as opposed to GetActualIncomingDamage() (I know one difference is the fact that GetEstimatedDamageToTarget() also takes items into account) and as my hero was tracking a potential target, I had the following output on the same creep (the health differences in the found lines are because the enemy creep kept taking hits from my own creeps ).

    Anyhow, I colored what I find strange.

    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 262
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 262
    [VScript] estimated2 262
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 262
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 69 * 77.28
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 262
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 40 * 44.8
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 40 * 44.8
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 40 * 44.8
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 262
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 40 * 44.8
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 262
    [VScript] estimated2 111
    [VScript] estimated3 126
    [VScript] found npc_dota_creep_badguys_melee * 40 * 44.8
    [VScript] target 230.55511474609 * 76.851704915365 * 1
    [VScript] estimated1 111
    [VScript] estimated2 111
    [VScript] estimated3 126
    Here are the 3 estimate calls.
    Code:
    print("estimated1 " .. self:GetEstimatedDamageToTarget(true, weakestCreep, self:GetAttackPoint() + UnitUtils.GetApproxTimeToReachLocation(self, weakestCreep:GetLocation()) + 0.10, DAMAGE_TYPE_PHYSICAL));
    print("estimated2 " .. self:GetEstimatedDamageToTarget(false, weakestCreep, self:GetAttackPoint() + UnitUtils.GetApproxTimeToReachLocation(self, weakestCreep:GetLocation()) + 0.10, DAMAGE_TYPE_PHYSICAL));
    print("estimated3 " .. weakestCreep:GetActualIncomingDamage(self:GetAttackDamage(), DAMAGE_TYPE_PHYSICAL));
    Since GetEstimatedDamageToTarget() is my concern, you will see the calls are identical between estimated1 and estimated2, the first parameter (bCurrentlyAvailable - which I gather means it either takes into account cooldowns as such when true, or ignores them when false, correct?), other than that, same params.
    To get the differences, I tested on a level 1 Wraith King WITHOUT any skills, only with a Deadalus in his inventory.
    My questions here:
    1. When the creep reaches 77.2, you will notice estimated1 goes from 262 to 111, then back to 262; I will assume it's because of the crit chance. Correct?
    2. When the creep reached 44.8 HP you will see that the 2 estimated damages, 111 and 262, get swapped. Why ?! If we assume that it's because of the crit chance, then why wouldn't the false parameter offer a consistent return value ? (remember, SK doesn't have any learned abilities or talents and no other items in his inventory)

    So, overall, I'd ask why are the return values so inconsistent?

    Another test I performed was with a Dagon5 just to eliminate any proc-chance that might interfere with the result. I changed the damage type to magical, restarted the game and only gave a Dagon5 to a level 1 WK without any abilities, talents or other items. Both estimated1 and estimated2 return 0 (?????). This was unexpected. Any ideas why? (apart from the obvious of who'd use a dagon on a creep )
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  2. #22
    Basic Member
    Join Date
    Oct 2016
    Posts
    220
    Quote Originally Posted by Platinum_dota2 View Post
    npcBot.HeroesInNeed only is available for alchemist. Before #npcBot.HeroesInNeed > 0, make sure it is not nil first. Also in the part where you check whether a hero has aghs, also look for aghs buff (so that you don't give aghs to someone twice).
    thanks

    Code:
    		if string.find(npcBot:GetUnitName(), "npc_dota_hero_alchemist") and npcBot.HeroesInNeed ~= nil then -- and #npcBot.HeroesInNeed > 0 then  -- counts properly but wont buy if comparing number, buy number will show up in print
    		print("Need to purchase   "..  #npcBot.HeroesInNeed)
    		PurchaseScepter();
    		end

    this is the simple code i am trying to run in ItemPurchaseGeneric, when the npcBot:HeroesInNeed > 0 is removed, he buys a scepter, if i put it in, he bypasses it. but as i have written in my comment to myself, the count works, but when used there it doesnt..... which i find extremely weird.

    as far as i have seen :HasScepter() incorporates the modifier too, but i generally use both just incase.

  3. #23
    Basic Member
    Join Date
    Oct 2016
    Posts
    220
    Quote Originally Posted by The Nomad View Post
    There are three (unofficial !! that means I categorize them as being three based on their behavior so they are not actual names ) types of tables in Lua:
    [LIST][*] a cleanly indexed table: this is the kind of table where you don't put anything in the {} table manually or add it via members, but use table.insert(); using it this way makes the table always start at index 1
    Therefore, an example would be:
    Code:
    local example_table = {} -- this is a not-null empty table; that means running if (example_table ~= nil) will return true, but #example_table returns 0 because there is nothing in it
    
    -- to populate it, we use insert from the table library:
    table.insert(example_table, "foo");
    table.insert(example_table, "bar");
    
    -- this means we know have a table that has index [1] as "foo" and index [2] as "bar"; this also means each new insert adds a new sequential index (that means it will add each element at 1, 2, 3, 4 ... n where n would be the last time you called table.insert()  )
    -- in order to get a proper indexed table you must only use table.insert(); if you do example_table[99] = "test" (which is legal) will not guarantee the sequence
    There are 2 ways to use indexed tables:
    Code:
    for key, value in pairs(example_table) do
        print(key .. " " .. value); -- we know that we only assigned strings as values
    end
    It's fine and it might output 1 foo and 2 bar; but there are cases where it might output 2 bar and 1 foo (that means the order is not necessarily done or guaranteed via the index). table.sort doesn't guarantee that iterating will be done in its proper order either
    To get over this issue we can use the second way:
    Code:
    for key, value in ipairs(example_table) do
        print(key .. " " .. value); -- we know that we only assigned strings as values
    end
    This guarantees it uses the indexes sequence. I had this issue with item purchases and took me some time to find the issue.
    Indexed tables can also use the # operator to get the number of elements and will always work. Please note that # doesn't really get the total element count, but the last sequence, if I remember correctly; therefore table.insert() is the recommended method to ensure a correct # result (or when using it on tables returned from C++ functions such as GetTeamMembers() or GetNearbyCreeps() and so on)

    To access an element you use their index: example_table[1] (which would return "foo" in our case)
    Removing it is done via its index: table.remove(example_table, 1) will remove "foo" and now example_table[1] will be "bar".
    Updating it is done explicitly: example_table[1] = "foo2"; So since we removed "foo" above, [1] will now be "foo2" instead of "bar".
    [*] non-indexed tables; most of the time used with strings (this assumes you use strings as keys for all values)
    The first issue is that # won't work on those tables (or, if it does work, it might have unexpected or inconsistent results in some cases).

    Adding values is done explicitly:
    Code:
    local example_table = {}
    
    example_table["element1"] = "foo";
    example_table["element2"] = "bar";
    Updating it is done the same way:

    Code:
    example_table["element2"] = "new bar";
    So element_table["element2"] will not contain "new bar" instead of "foo".

    To remove it:
    Code:
    example_table["element1"] = nil;
    Please note that if we removed it from the example, the table will now have a value in example_table["element2"]; element2 DID NOT replace element1 !!. Therefore example_table["element1"] prints nothing, example_table["element2"] will print "new bar" (since we renamed it earlier)

    The way to get the number of elements is by looping them:
    Code:
    function GetTableLength (tTable)
    	local length = 0;
    
    	if (tTable ~= nil) then
    		for _ in pairs(tTable) do
    			length = length + 1;
    		end
    	end
    
    	return length;
    end
    
    print("the element count is " .. GetTableLength(example_table));
    [*] inconsistent tables (no idea how to call these) are those tables that have either a string or a number as keys at the same time (so not one or the other). I really, really, really, really don't recommend doing this. It's difficult to maintain and traverse. The only way to get the leement count is with an iterating function like above.

    Long story short, the most reliable (and recommended) way to get the count is to use an iterating function like in the example above. Honestly, I don't know why Lua doesn't add a proper method, but whatever.

    So, depending on what kind of table it is you can use # or an iterating function. From the picture I see that it uses indexed keys so # should be ok, just keep in mind that the element on the next position replaces the element on the deleted position. That means, to delete lion you can use table.remove(my_table, 3). But afterwards, if you want to delete shadow shaman you must use table.remove(my_table, 3), not table.remove(my_table, 4).

    As for, why # doesn't work, it depends on whom you call it upon. It doesn't add that member to ALL bots. It's only visible to the one that was added. Ah, seems Platinum beat me to this
    I think it will help if you show us the code.

    EDIT:

    The table key index IS NOT the player id. So don't use GetPlayerID() in table.remove. GetPlayerID() is also zero-indexed, while tables (normally) aren't.
    gah, sorry about quoting all that, too much to edit down.
    So, does all that mean the easiest way for me to get alchemist to remove the correct person he fed the scepter to from the table is for him to re-sort the table so his target is [1] in the index, then remove [1]?

    i mean i could simply have him feed to target one, then remove that, but again its the "me" way of doing things and it isnt very versatile or elegant
    Code:
    feedsceptor_target = npcBot.HeroesInNeed[1];
    npcBot:Action_UseAbilityOnEntity(GetItemByName("item_ultimate_scepter") , feedsceptor_target);
    table.remove(npcBot.HeroesInNeed, 1)
    that would work yea?

    or perhaps i will keep reading and thinking about what you said about updating the values.
    eg. if he chooses to feed to no.3 in the table, i could get the names of no.3 and no.1 and swap them around?
    but with timings, would this likely ever replace one before another and end up with a clone and the other value wiped out?
    if i swapped the values too early, could this make his feed break? for instance, if i put the table swap script into the above example like so:
    (not that this should be too early)
    Code:
    feedsceptor_target = Target_Based_on_Other_Conditions;
    npcBot:Action_UseAbilityOnEntity(GetItemByName("item_ultimate_scepter") , feedsceptor_target);
    
    (update name of position 3 to position 1 and vise versa here)
    
    table.remove(npcBot.HeroesInNeed, 1)


    The code im using for feed so far is just 0838 (alch and friends?) feed code, but i think i will basically rewrite it because its a bit more complicated than i need for the same job now.
    Code:
    function feedsceptor()
    	local npcBot = GetBot();
    	local feedsceptor_target = nil;
    	if ( CheckItemByName ( "item_ultimate_scepter" ) and GetItemByName("item_ultimate_scepter"):IsFullyCastable() ) then
    		local AllyHero = GetUnitList( UNIT_LIST_ALLIED_HEROES );
    		local lowest_distance = 99999;
    		for k, hero in pairs(AllyHero) do
    			local ID = hero:GetPlayerID();
    			local HeroName = hero:GetUnitName();
    			if ((not IsPlayerBot(ID)) and (not hero:IsIllusion()) and GetVarInTable( HeroName, SceptorList ) ~= 0 and (not hero:HasScepter() ) and GetUnitToUnitDistance(npcBot, hero) < lowest_distance)
    			or ((IsPlayerBot(ID)) and (not hero:IsIllusion()) and GetVarInTable( HeroName, npcBot.HeroesInNeed ) and (not hero:HasScepter()) and GetUnitToUnitDistance(npcBot, hero) < lowest_distance) then
    				feedsceptor_target = hero;
    				lowest_distance = GetUnitToUnitDistance(npcBot, hero);
    			end
    		end
    	end
    	return feedsceptor_target;
    end
    
    			--or ((IsPlayerBot(ID)) and (not hero:IsIllusion()) and GetVarInTable( HeroName, SceptorList ) ~= 0 and (not hero:HasScepter() and not utils.WillBuyScepter(hero) ) and GetUnitToUnitDistance(npcBot, hero) < lowest_distance) then
    
    
    function gofeedsceptor()
    	local npcBot = GetBot();
    	local feedsceptor_target = feedsceptor();
    	if (npcBot:IsUsingAbility() )then
    		return;
    	end
    
    	if feedsceptor_target ~= nil then
    	print("Feeding to   ".. feedsceptor_target:GetUnitName())
    	npcBot:Action_UseAbilityOnEntity(GetItemByName("item_ultimate_scepter") , feedsceptor_target);
    	table.remove(npcBot.HeroesInNeed, feedsceptor_target:GetPlayerID()) -- 1 is first guy, wants number, but we want to remove feedsceptor_target
    	end
    end
    this is in purchase generic (dont worry about the missing end, there is more role based buying below it)

    Code:
    	if #(npcBot.tableItemsToBuy) == 0 then
    		
    		if string.find(npcBot:GetUnitName(), "npc_dota_hero_alchemist") and npcBot.HeroesInNeed ~= nil then -- and #npcBot.HeroesInNeed > 0 then  -- counts properly but wont buy if comparing number, buy number will show up in print
    		print("Need to purchase   "..  #npcBot.HeroesInNeed)
    		PurchaseScepter();
    		end
    this is Platinums code up top of alchemists ability usage file.

    Code:
     
      -------- Scepter Check for Alch to feed -  -------------
    	if DotaTime() > 1 * 60 and ScepterCheckOnce == false then
    
    		--if npcBot:GetUnitName()=="npc_dota_hero_alchemist" then
    		--	npcBot.HeroesInNeed={};
    			for i=1,5,1 do
    				local ally=GetTeamMember(i);
    				if ally~=nil and ally.NeedsScepter~=nil and ally.NeedsScepter then
    				table.insert(npcBot.HeroesInNeed, ally:GetUnitName()); -- or insert ally:GetUnitName() /maybe ally:GetPlayerID() for removal later
    				end
    			end
    			print(npcBot:GetUnitName())
    			utils.print_r(npcBot.HeroesInNeed)
    		--else
    			--npcBot.NeedsScepter = not utils.HasSomeBuild("item_ultimate_scepter");
    		--end
    	ScepterCheckOnce = true;
    	end
    and this is the relevant part of abaddons build file

    Code:
    npcBot.NeedsScepter = true;
    X["items"] = {		
    	"item_magic_wand",	
    	"item_arcane_boots",
    	"item_mekansm",
    	"item_drums_of_endurance",
    	"item_vladmir",
    	"item_guardian_greaves",
    	"item_orchid",
    	"item_dagon_5",
    };
    Last edited by Yavimaya; 06-22-2017 at 05:24 PM.

  4. #24
    Basic Member
    Join Date
    Oct 2016
    Posts
    220
    thanks for all your help guys.
    i didnt end up going the better, but harder way.
    i dumbed it down, but used some of what was written for me.
    i wouldnt have come up with the solution without you.

    i can post the code if you guys want a quick implementation of alch feeding to only the bots who need it, but its crude and spread over multiple files, its basically what is above, but working.

  5. #25
    Basic Member
    Join Date
    Dec 2016
    Posts
    178
    Is there anyway to find enemy creeps's current attack target? GetAttackTarget() return nil for enemy lane creeps.

  6. #26
    Valve Developer
    Join Date
    Sep 2011
    Posts
    1,704
    Quote Originally Posted by The Nomad View Post
    So, overall, I'd ask why are the return values so inconsistent?
    It's definitely due to the Daedalus and the way it estimates crits.

  7. #27
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,866
    I thought that in the case of Deadalus, if the bCurrAvailable param is true it assumes I have 100% crit chance while false assumes I have the actual item chance. Otherwise I don't see the point of this param in such scenarios, or did I misunderstand its purpose for crit items/abilities? (I know it's mainly for cooldown abilities and items, but I am referring to proc items/abilities)
    Last edited by The Nomad; 06-28-2017 at 04:15 PM.
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  8. #28
    Valve Developer
    Join Date
    Sep 2011
    Posts
    1,704
    bCurrAvailable will exclude the usage of any abilities that are on cooldown, or that you don't have the mana to cast. It doesn't take into account procs at all.

    And yeah, the way the function handles procs is less than optimal.

  9. #29
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,866
    But at least now it is clear Thanks for the explanations
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •