Page 2 of 3 FirstFirst 1 2 3 LastLast
Results 11 to 20 of 29

Thread: Simple questions, Simple answers

  1. #11
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,769
    How about inside each item_pruchase file, check if the scepter is inside the item list and if not, update a table member on Alchemist.

    Inside the item_purchase files just do GetTeamMembers() then iterate through all available members using GetTeamMember(). If that hero is Alchemist, add it.

    Code:
    -- item_purchase_lina
    
    local function NotifyAlchemist ()
    	local playerList = GetTeamPlayers(GetTeam());
    
    	for teamPlayerID, gamePlayerID in pairs(playerList) do
    		if (IsTeamPlayer(gamePlayerID) == true) then
    			heroName = GetSelectedHeroName(gamePlayerID);
    
    			if (heroName == "npc_dota_hero_alchemist")  then
    				if (GetTeamMember(teamPlayerID).ScepterCount == nil) then
    					GetTeamMember(teamPlayerID).ScepterCount = 1;
    				else
    					GetTeamMember(teamPlayerID).ScepterCount = (ScepterCount + 1);
    				end
    			end
    		end
    	end
    end
    Obviously you can use a table that you can then, call table.insert on
    The advantage here is that then you can call the Think() on your Alchemist or in his item list using GetBot().ScepterCount.

    The trick here is to find a good way to call the notify function above to avoid infinite calls. Minor note: the above example is just that: an example. Since it's a local function it will only be called from inside the file so make sure you either make it global OR add it as a table member to access it from other files using require().

    If you need help, let us know.
    Last edited by The Nomad; 06-21-2017 at 10:58 PM.
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  2. #12
    Basic Member
    Join Date
    Oct 2016
    Posts
    210
    thanks nomad, i kind of need help just understanding that.
    im with you, but i dont use separate purchases for each bot, this would also work the same in a purchase generic file i gather, because each bot checks itself and adds its name to "alchemist.ScepterNeededTable" for eg.?

  3. #13
    Basic Member
    Join Date
    Oct 2016
    Posts
    210
    i tried your example and kept getting main chunk errors, so i tried again using what i generally know how to do with what you said mixed in.

    Code:
    if DotaTime() < 0 then
    	local TotalScepterCount = 0;
    	local numPlayer =  GetTeamPlayers(GetTeam());
    	if not string.find(npcBot:GetUnitName(), "npc_dota_hero_alchemist") then
    		if not HasSomeBuild("item_ultimate_scepter") then
    		print(npcBot:GetUnitName().. " - Needs Scepter -  ")
    			for i = 1, #numPlayer do
    				if string.find(GetTeamMember(i):GetUnitName(), "npc_dota_hero_alchemist") then
    				GetTeamMember(i).TotalScepterCount = GetTeamMember(i).TotalScepterCount + 1
    				table.insert(GetTeamMember(i).NeedsScepter, npcBot:GetUnitName())
    				utils.print_r(GetTeamMember(i).NeedsScepter.. "  Needs scepter")
    				end
    			end
    		end
    	end
    end
    [ W VScript ]: Script Runtime Error: ...ame\dota\scripts\vscripts\bots\item_purchase_ge neric.lua:1086: bad argument #1 to 'find' (string expected, got boolean)
    [ W VScript ]: stack traceback:
    [ W VScript ]: [C]: in function 'find'
    [ W VScript ]: ...ame\dota\scripts\vscripts\bots\item_purchase_ge neric.lua:1086: in main chunk

    is the error im getting when calling method :GetUnitName() on GetTeamMember(i), yet any other method - GetNeabryHeroes, etc. work just fine.

  4. #14
    @Yavimaya

    Code:
    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); -- or insert ally:GetUnitName()
    		end
    	end
    else
    	npcBot.NeedsScepter = not HasSomeBuild("item_ultimate_scepter");
    end
    Last edited by Platinum_dota2; 06-21-2017 at 09:10 PM.

  5. #15
    Basic Member
    Join Date
    Oct 2016
    Posts
    210
    thats script looks like exactly what i need Platinum, thank you heaps, you too nomad.

    so just to be clear, that goes into its own function that i can just call once at the start of game and then from alchs script i can just call on the table for number or people and name of them (once i insert ally:getunitname())?

    edit again: thank you, that is perfect, once i put the prints in can see more clearly how it all works.
    sorry im just terrible at making stuff from scratch.
    Last edited by Yavimaya; 06-21-2017 at 10:28 PM.

  6. #16
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,769
    Quote Originally Posted by Yavimaya View Post
    i tried your example and kept getting main chunk errors, so i tried again using what i generally know how to do with what you said mixed in.

    Code:
    if DotaTime() < 0 then
    	local TotalScepterCount = 0;
    	local numPlayer =  GetTeamPlayers(GetTeam());
    	if not string.find(npcBot:GetUnitName(), "npc_dota_hero_alchemist") then
    		if not HasSomeBuild("item_ultimate_scepter") then
    		print(npcBot:GetUnitName().. " - Needs Scepter -  ")
    			for i = 1, #numPlayer do
    				if string.find(GetTeamMember(i):GetUnitName(), "npc_dota_hero_alchemist") then
    				GetTeamMember(i).TotalScepterCount = GetTeamMember(i).TotalScepterCount + 1
    				table.insert(GetTeamMember(i).NeedsScepter, npcBot:GetUnitName())
    				utils.print_r(GetTeamMember(i).NeedsScepter.. "  Needs scepter")
    				end
    			end
    		end
    	end
    end
    [ W VScript ]: Script Runtime Error: ...ame\dota\scripts\vscripts\bots\item_purchase_ge neric.lua:1086: bad argument #1 to 'find' (string expected, got boolean)
    [ W VScript ]: stack traceback:
    [ W VScript ]: [C]: in function 'find'
    [ W VScript ]: ...ame\dota\scripts\vscripts\bots\item_purchase_ge neric.lua:1086: in main chunk

    is the error im getting when calling method :GetUnitName() on GetTeamMember(i), yet any other method - GetNeabryHeroes, etc. work just fine.
    Just for further info on your part:
    - you don't need string.find on GetUnitName() vs an actual hero internal name. Using ~= or == works fine and is actually better in terms of performance; use string.find ONLY for patterns or portions of text
    - string.find is mostly used for patterns rather than portions of text; you will find that string.find("shell32.dll, ".") return 1 when in fact it should return 8; you would have to add 2 more params: string.find("shell32.dll", ".", 1, true) - 1 meaning "start at position 1" and true meaning "it's not a regex, but a plain text match". But as said, don't use it if you don't have to
    - depending on when you call that code piece, it will always run while DotaTime() < 0; what I mean is, YES, it won't always add scepters since you added the "if not HasSomeBuild", however, it will run the prior part, meaning GetTeamPlayers() and string.find() for the full duration of almost 2 minutes. While nothing exciting happens in that time and they are not the most expensive functions in the world, keep that in mind for future code design
    - you probably got the "bad argument #1 to find" because you used npcBot but didn't assign it with npcBot = GetBot() anywhere - or at least I don't see it in that snippet; GetTeamMember() returns a handle similar to that of GetBot() which is why you say one works and the other doesn't

    Good luck !
    Explanations on the normal, high and very high brackets in replays: here, here & here
    Why maphacks won't work in D2: here

  7. #17
    Basic Member
    Join Date
    Oct 2016
    Posts
    210
    thanks nomad.
    GetBot should have been assigned at the start of the file (it was run within ItemPurchaseThink()), but you are correct, it was a stupid place to put it, Platinums is now up top of the itempurchase file and only runs once. much better.
    im really not sure about the bad argument, as far as i could see i was passing it all the variables it needed, but as ive said before, im a bit slow lol.
    back in school, in maths, a teach would walk me through an example, then change the numbers for me to do it and i was back to square one. :sad:

    Edit:
    seems up top of ItemPurchase or ItemAbilityGeneric arent the right places, table is printing as empty unless i reload.
    Where might one put this or what condition might i put in so it only runs once, but after the tableItemsToBuy is filled? - Ignore that, ill just use a variable to stop it running more than once.

  8. #18
    Basic Member
    Join Date
    Oct 2016
    Posts
    210
    update:
    after running many test runs, im not 100% sure it is working properly, underlord put himself into the table in one game when his build wanted an ulti scepter.
    in the same game, antimage printed that he wont buy a scepter, but didnt add himself to table, also wisp who never buys scepter didnt put himself into the table (wisp is just for testing)
    many other tests it has been hard to determine if it worked because starting items are all the same for some people, but it generally looked to work every other time.

    sceptTable.jpg
    this is the result after making it loop twice, first loop historically has printed an empty table.

    update2:
    ive stripped out the "HasSomeBuild" part and decided to manually put the npcBot.NeedsScepter into each hero build file.
    its not as elegant or versitile as i would have liked, but it removes the problems that were occurring.

    thanks again.

    now, how do i call the count of the table? #npcBot.HeroesInNeed > 0 doesnt seem to work. thats the only way i know of to get the table length.
    also would "table.remove(npcBot.HeroesInNeed, feedsceptor_target:GetPlayerID())" be the way to remove the right hero from the table, since it wants a number? (feedscepter_target:GetUnitName() doesnt work)
    Last edited by Yavimaya; 06-22-2017 at 03:57 AM.

  9. #19
    Quote Originally Posted by Yavimaya View Post
    update:
    now, how do i call the count of the table? #npcBot.HeroesInNeed > 0 doesnt seem to work. thats the only way i know of to get the table length.
    also would "table.remove(npcBot.HeroesInNeed, feedsceptor_target:GetPlayerID())" be the way to remove the right hero from the table, since it wants a number? (feedscepter_target:GetUnitName() doesnt work)
    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).

  10. #20
    Basic Member
    Join Date
    Mar 2012
    Posts
    1,769
    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:
    Quote Originally Posted by Yavimaya View Post
    also would "table.remove(npcBot.HeroesInNeed, feedsceptor_target:GetPlayerID())" be the way to remove the right hero from the table, since it wants a number? (feedscepter_target:GetUnitName() doesnt work)
    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.
    Last edited by The Nomad; 06-22-2017 at 07:48 AM.
    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
  •