#๐Ÿ”’ Bird Trading Code Review

787 messages ยท Page 1 of 1 (latest)

grizzled glacierBOT
#

@regal adder

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

regal adder
#

The duplication prevention doesn't work yet and I'd like to add in a real life time-based element for determining which birds spawn as well. Overall, I'd just like to try and simplify/optimize my code because it's getting to be a bit much and I don't know I'm doing things the best way they can be done yet.

clear thorn
# regal adder I'm trying to optimize my code here. https://paste.pythondiscord.com/AQSQ
        for i in range(0, len(available_items)):
            if i[i] == item_selection:
                item_selection.pop(i)

Well, this has a few issues. i[i] is using the index instead of a list, and item_selection.pop(i) doesn't seem to be the one you want to remove things from, right?

A list comprehension like this would probably be better:
available_items = [item for item in available_items if item != item_selection]
That rebuilds the list with everything that isn't the current selection.

It should also probably be done inside the for loop where you're picking the items, not after it. Right now you do the selections and then remove the last item selected from the available list.

#

For optimizing, you're doing basically the same thing across three different bird lists, so it would make sense to create a single function and call it for each of them, passing the item lists and such as parameters.

regal adder
# clear thorn ```python for i in range(0, len(available_items)): if i[i] =...

Hm. So if I understand that right, it would be like this, yes?

    if bird_species in bird_list_common:
        for item in item_list_common:
            if item[2] <= player_reputation:
                available_items.append(item)
        for i in range(0, bird_items_offered_count):
            item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
            item_selection_list.append(item_selection)
            available_items = [item for item in available_items if item != item_selection]
clear thorn
regal adder
#

That appears to prevent duplication until it runs out of items in the list, in which case it resets to the original list.

#

Yeah, so how do I prevent it from resetting to the original list once the list with removals becomes empty or there's not enough of them to fill up the item_selections_list?

#

[True, True, True, False, False]
BIRD SPAWN # 0
BIRD SPECIES Courigon
------Courigon 100 4------
['Tumbled Agate', 'Shiny Pebble', 'Tumbled Agate', 'Shiny Pebble']
BIRD SPAWN # 1
BIRD SPECIES Courigon
------Courigon 100 4------
['Shiny Pebble', 'Tumbled Agate', 'Lost Mail', 'Shiny Pebble']
BIRD SPAWN # 2
BIRD SPECIES Trinketalon
------Trinketalon 100 4------
['Rations', 'Rations', 'Wrist - Wraps - Bloodied', 'Rations']
BIRD SPAWN # 3
BIRD SPAWN # 4

#

Or maybe it's just not preventing the duplications at all and I missed something?

clear thorn
#

Are you wanting to prevent duplications across any birds? Or just the same bird?

regal adder
#

Duplications of items.

#

So if it selects a bird from the common list, I don't want it to offer 4 Shiny Pebbles for example.

#

If the list is too small for it to give the full amount of offers, it should only give the amount it can instead of duplicating too.

clear thorn
#

Ah, gotcha

#

Couple changes then. You'll want to check at the start of the loop to make sure there's still items in available_items and break if you've run out

#

Also missed that the items are tuples, so your list comprehension should be [item for item in available_items if item[0] != item_selection]. Because you need to compare the names

#

That's why it wasn't catching the duplicate, sorry about that

regal adder
#

Oh, no worries at all. You're teaching me too so I appreciate all the help!

#

So would a good check for that be

if bird_items_offered_count < len(item_selection_list):
```?
#

It did not like that.

clear thorn
# regal adder So would a good check for that be ```py if bird_items_offered_count < len(item_s...

In the loop right now you run for whatever the bird_items_offered_count is, and the available_items list is what's going to eventually run out and cause issues.

So you can either check to see which is smaller, something like min(bird_items_offered_count,len(available_items)) and use that for your loop range, or you can check the length of available_items at the start of the loop and, if it's empty, break out.

regal adder
#

Oh I think I put the < the wrong way.

#

Oh so instead of this.

    if bird_species in bird_list_rare:
        for item in item_list_rare:
            if item[2] <= player_reputation:
                available_items.append(item)
        for i in range(0, bird_items_offered_count):
            print(f'COUNT {bird_items_offered_count} LIST {item_selection_list}')
            if bird_items_offered_count > len(item_selection_list):
                item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
                item_selection_list.append(item_selection)
                [item for item in available_items if item[0] != item_selection]
#

I'd do this.```py
if bird_species in bird_list_rare:
for item in item_list_rare:
if item[2] <= player_reputation:
available_items.append(item)
for i in range(0, min(bird_items_offered_count,len(available_items))):
print(f'COUNT {bird_items_offered_count} LIST {item_selection_list}')
item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
item_selection_list.append(item_selection)
[item for item in available_items if item[0] != item_selection]

#

Am I understanding you correctly?

clear thorn
#

Looks right. That should run for either the offer count, or how many items there are to offer, whichever one is smaller.

regal adder
#

Hm. It's close.

#

[True, False, False, False, True]
BIRD SPAWN # 0
------Courigon 100 4------
COUNT 4 LIST []
COUNT 4 LIST ['Lost Mail']
COUNT 4 LIST ['Lost Mail', 'Tumbled Agate']
['Lost Mail', 'Tumbled Agate', 'Shiny Pebble']
BIRD SPAWN # 1
BIRD SPAWN # 2
BIRD SPAWN # 3
BIRD SPAWN # 4
------Courigon 100 4------
COUNT 4 LIST []
COUNT 4 LIST ['Tumbled Agate']
COUNT 4 LIST ['Tumbled Agate', 'Shiny Pebble']
['Tumbled Agate', 'Shiny Pebble', 'Tumbled Agate']

#

It's adding an additional one on there though?

clear thorn
#

[item for item in available_items if item[0] != item_selection] this isn't being assigned to available_items

#

You're just building the new list and tossing it lol

regal adder
#

Oh woops.

#

It works!

#

Thank you so much for your help!

#

So then to optimize my code, what would I call the current function and then the function that properly generates the item list?

#

Maybe get_bird_rarity and then generate_bird_item?

clear thorn
#

Yeah, ideally you'd take what you have there and make it into a function that you can then call for every bird list, instead of copying the changes over to repeat the instructions for each one

#

Makes it easier to read and debug, and if you change it in the future you only have to adjust in one place and not multiple

regal adder
#

Yeah, let me see if I can manage that and then submit for your approval.

#

Hm. This is very confusing.

#

Okay I think I got that part right but now it's saying that it can't compare a tuple to an int for the ```py
if item[2] <= player_reputation:

#

Because item[2] is equal to ('Lost Mail', 10, 20).

#

The whole tuple.

#

But it was indexing into the tuple before so I'm not sure what changed.

#

Because now item is a list???

#

Here, this is what I have right now.

#

Not understanding what changed and why item is now a list.

#

You seeing any clue of what I did incorrectly?

#

OH.

clear thorn
# regal adder You seeing any clue of what I did incorrectly?

Track back through the function calls. So here's our issue, item_list is no longer a list of items. So something is calling this function wrong:
generate_bird_items(item_list, bird_species)

That happens up in generate_bird_spawns, with this: generate_bird_items(get_bird_rarity(bird_spawns[i]), bird_spawns[i])

So the item list we're feeding is whatever get_bird_rarity() returns. Which is this:

if bird_species in bird_list_common:
        return item_list_common, bird_species
    if bird_species in bird_list_uncommon:
        return item_list_uncommon, bird_species
    if bird_species in bird_list_rare:
        return item_list_rare, bird_species

Tuples

regal adder
#

I see.

#

That is not what I intended.

#

How do I return the item_list and bird_species separately then?

clear thorn
#

You don't. You get one return call from a function, so they have to be returned as a tuple, a list, some way of packaging them together. You need to split them up after they're returned.

regal adder
#

Hmmmm okay.

clear thorn
#

Assuming you need them both returned at all, are you even using the bird species from this?

regal adder
#

I understand.

#

Yes, bird_species goes into the get_player_reputation.

#

Because reputation differs depending on the species.

clear thorn
#

Right, but you already do that

#
                bird_spawns[i] = generate_bird_species()
                generate_bird_items(get_bird_rarity(bird_spawns[i]), bird_spawns[i])
regal adder
#

I'm not sure I follow.

#

Oh like I could call get_player_reputation there and then it would be passed into generate_bird_items as an argument?

clear thorn
#

You generate a bird species and assign it to bird_spawns[i]
You then get the bird rarity by passing it the species. That function returns the item list and the species, which you already have, because you gave it to the function in the first place

#
def get_bird_rarity(bird_species): #Bird species is given to this function
...
    if bird_species in bird_list_common:
        return item_list_common, bird_species #You return the item list, and also the bird species that was given to the function
#

So basically you don't need to return both, you don't use it, you just need the item list

regal adder
#

I'm honestly very confused.

clear thorn
#

When you call generate_bird_items(get_bird_rarity(bird_spawns[i]), bird_spawns[i])

You're giving it two arguments:
(get_bird_rarity(bird_spawns[i]), bird_spawns[i]

The first one is your function, which returns an item list and a bird species.
The second one is a bird species

regal adder
#

Yes.

clear thorn
#

get_bird_rarity() doesn't need to return a bird species

#

You already have it

#

That argument is just for the item list

regal adder
#

Okay I think I understand.

#

One moment.

#

It works!

clear thorn
#

๐ŸŽ‰

regal adder
#

Need to add functionality for actually naming the locations based on the town like oh it's in Town X, so it's on Fence 1, and stuff like that but that shouldn't be too hard. Then I can add functionality for making it so some bird species are IRL time-locked so the owl ones only come out at night.

#

Thank you so much for all your help again. You are a godsend!

clear thorn
#

Sure thing, glad you got it working ๐Ÿ˜„

regal adder
#

Do you have any interest in working on video games?

clear thorn
#

Not at the moment, but that is how I got started in Python lol

regal adder
#

Ah fair enough. I'm trying to build out the basic functionality for this feature in Python now since I kind of know Python and don't know any C++ for Unreal.

clear thorn
#

Solid plan. The more you practice and work with it, the faster and better you'll be at it. Even if you decide to learn C++ down the road, a decent bit of the logic will carry over.

regal adder
#

Hopefully! If you meet anyone who'd like to work on something like Pokemon but better, let me know! I'd always appreciate the help.

regal adder
# clear thorn Solid plan. The more you practice and work with it, the faster and better you'll...

Sorry to bug you one more time, but how might I implement time-locked spawns here? I've got the time ranges I'd like them to be potentially active for but I'm not sure of the best way to implement it.

def generate_bird_species():
    rarity_list = [("Common", 80), ("Uncommon", 15), ("Rare", 5)]
    #Bird_list format is ("Species", Probability, Beginning Spawn Time, End Spawn Time)
    bird_list_common = [("Courigon", 100, "4:00:00", "20:00:00")]
    bird_list_uncommon = [("Trinketalon", 90,  "4:00:00", "20:00:00"), ("Baublekaw", 10,  "20:00:00", "8:00:00")]
    bird_list_rare = [("Hautehoot", 90,  "22:00:00", "4:00:00"), ("Vogueowl", 10,  "22:00:00", "4:00:00")]
    rarity_selection = random.choices(population=[i[0] for i in rarity_list], weights=[i[1] for i in rarity_list], k=1)[0]
    if rarity_selection == "Common":
        bird_species = random.choices(population=[i[0] for i in bird_list_common], weights=[i[1] for i in bird_list_common], k=1)[0]
    elif rarity_selection == "Uncommon":
        bird_species = random.choices(population=[i[0] for i in bird_list_uncommon], weights=[i[1] for i in bird_list_uncommon], k=1)[0]
    elif rarity_selection == "Rare":
        bird_species = random.choices(population=[i[0] for i in bird_list_rare], weights=[i[1] for i in bird_list_rare], k=1)[0]
    return bird_species
clear thorn
regal adder
#

I'm somewhat familiar with classes and you do have a point. Would everything then go into the bird class?

clear thorn
clear thorn
regal adder
regal adder
clear thorn
# regal adder Yes, I understand the logic for it, I just don't know how to implement it in the...

You'll use the time objects in the module:
https://docs.python.org/3/library/datetime.html#time-objects

datetime.datetime.now() gives you the current date and time, and then you can call .time() on that to just get the time. Similarly, you can set variables to hold the start and end times by building them with datetime.time(hour,minute,second). The hour, minute, second would come from the start and end times you've saved.

#

Once you have your start, end, and current time you can compare them like you would regular integers. Later times will be greater than earlier times.

clear thorn
regal adder
#

I did this to get the time but they probably both work. ```py
current_datetime = datetime.now()
current_time = current_datetime.strftime("%H:%M:%S")
print(f'DATETIME {current_datetime} TIME {current_time}')

regal adder
#

And here's what I have so far for the class.

class OfferingBird:
    def __init__(self, name, probability, spawn_time_start, spawn_time_end, possible_locations):
        self.name = name
        self.probability = probability
        self.spawn_time_start = spawn_time_start
        self.spawn_time_end = spawn_time_end
        self.possible_locations = possible_locations

#OfferingBird format: Name, Probability, Spawn Time Start, Spawn Time End, Possible Locations
OfferingBird1 = OfferingBird("Courigeon", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""])
OfferingBird2 = OfferingBird("Baublekaw", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""])
OfferingBird3 = OfferingBird("Trinketalon", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""])
OfferingBird4 = OfferingBird("Outflit", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""])
OfferingBird5 = OfferingBird("Hautehoot", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""])
OfferingBird6 = OfferingBird("Vogueowl", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""])
clear thorn
# regal adder I mean like I literally don't know what code you'd add for that because I'm not ...

Well, first you need to get the time variables set up so that you can compare them. So you'll still need to get your start, current, and end times as .time() objects. In your code snippet current_time is now a string, which you can't check times with > and <.

Then once you have them, you can just add it to the list comprehension when you're building the bird species to return:
[i[1] for i in bird_list_common if start_time < current_time and current_time < end_time]

clear thorn
regal adder
#

So then I'd rebuild the start and end times like this.
OfferingBird1 = OfferingBird("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", ""])

regal adder
#

So I have

current_datetime = datetime.now()
current_time = current_datetime.time()
...

#OfferingBird format: Name, Probability, Spawn Time Start, Spawn Time End, Possible Locations
OfferingBird1 = OfferingBird("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", ""])
OfferingBird2 = OfferingBird("Baublekaw", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", ""])
OfferingBird3 = OfferingBird("Trinketalon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", ""])
OfferingBird4 = OfferingBird("Outflit", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village", ""])
OfferingBird5 = OfferingBird("Hautehoot", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village", ""])
OfferingBird6 = OfferingBird("Vogueowl", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village", ""]
...

 bird_species = random.choices(population=[i[0] for i in bird_list_common if start_time < current_time < end_time], weights=[i[1] for i in bird_list_common], k=1)[0]

and then I'm not sure how to adapt this to be used by classes and without individual variables for each bird.

regal adder
#

Yeah, I'm not really understanding how I'd go about using classes in the flow of generating these. Could you provide an example of like how I'd integrate the generate_bird_spawns function into the class?

#

Don't know what sort of data type I should use for the possible locations either. Maybe dictionaries because each area will have a given number of spawns.

#

But could also do a list of tuples.

#

Or should that be it's own class? @clear thorn

#

Kind of spinning my wheels here.

#

OfferingBirdItems should be its own class for sure.

clear thorn
# regal adder So I have ```py current_datetime = datetime.now() current_time = current_datetim...

Basically you'd dynamically create the instances. You can do that by looping through the list of options if you just want one of each. The way you have it now you're creating a new variable every time you want to add a bird, and then you'd have to make sure that variable is included everywhere else those birds are referenced.

Doing something like this, all you have to do is add a new entry to the list of birds and it gets added automatically:

class OfferingBird:
    def __init__(self, name, probability, spawn_time_start, spawn_time_end, possible_locations):
        self.name = name
        self.probability = probability
        self.spawn_time_start = spawn_time_start
        self.spawn_time_end = spawn_time_end
        self.possible_locations = possible_locations

#A list of tuples for all the bird data, new birds just get a new one added to the list
bird_data = [("Courigeon", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""]),
("Baublekaw", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""]),
("Trinketalon", 80, "4:00:00", "20:00:00", ["Wellspring Village", ""]),
("Outflit", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""]),
("Hautehoot", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""]),
("Vogueowl", 80, "22:00:00", "4:00:00", ["Wellspring Village", ""])]

#A list for all the instances that you'll be sending to functions
all_birds = []

#Loop through all the options and make OfferingBird instances for each
for bird in bird_data:
    name, probability, start_time, end_time, locations = bird
    spawn_time_start = datetime.strptime(start_time, "%H:%M:%S").time()
    spawn_time_end = datetime.strptime(end_time, "%H:%M:%S").time()
    all_birds.append(OfferingBird(name, probability, spawn_time_start, spawn_time_end, locations))
regal adder
#

So this way just reuses the bird variable each time.

clear thorn
# regal adder Or should that be it's own class? <@262426987979735040>

You should make classes out of things that are going to have a lot of properties, and that you'll have a lot of copies of. Like the birds, you have a bunch of them and they all have the same type of properties but different values, so a class lets you more easily keep track of them.

If your locations aren't going to have properties, or only one or two, it might not be worth making a class for them.

#

Also, some people just like classes, so they make one for almost everything. It's personal choice.

regal adder
#

Locations will be like Town X, but then they'll have 3-8 bird spawn locations.

#

And I might add more properties later perhaps.

clear thorn
#

If you think it makes sense to have it as a class, go for it. If nothing else, you can always change it later if you don't like how it's turned out.

#

If you do a lot of comparing and referencing, it can make it easier. Like for your birds in my example, if you loop through all_birds after making the instances, you can check for values just by calling the property. bird.name gives you the name, bird.probability gives the probability, etc. No more messing with tuples and indexes

regal adder
#

Yeah, I can see the benefit. Just really struggling to understand how to implement them.

#

So we need to get_player_location so we know how many potential birds to spawn, and then for each one where it's True, we want to generate a bird and then generate its items_list.

#

Let me see if I can add comments so this makes more sense.

clear thorn
# regal adder Yeah, I can see the benefit. Just really struggling to understand how to impleme...

That comes with practice. It's difficult to plan out how you're going to use something when you're not terribly familiar with it. For the bird generation based on location, your basic logic could look like this:

player_location = get_player_location()
location_birds = [bird for bird in all_birds if player_location in bird.possible_locations]

Then you can do random.choice(location_birds) to get a random one, or something fancier with the probabilities

regal adder
#
class Player:
    def __init__(self, player_name, location_name):
        self.player_name = player_name
        self.location_name = location_name
        
    def get_player_location():
        #return self.location_name
        return "Wellspring Village"

class OfferingBird:
    def __init__(self, offering_bird_name, probability, spawn_time_range, locations_list, offering_list):
        self.offering_bird_name = offering_bird_name #String
        self.probability = probability #Integer
        self.spawn_time_range = spawn_time_range #Tuple
        self.locations_list = locations_list #List of Tuples
        self.items_list = offering_list #Object

    def generate_offering_bird_spawn_locations():
        bird_spawn_list = []
        player_location = get_player_location()
        if player_location == "Wellspring Village":
            #Get the locations_count number for that location from the associated OfferingBirdLocation object.
            for i in range(0, #locations_count)
            bird_spawn_list.append(random.choice([True, False]))
                #for each True in the bird_spawn_list
                    #generate an OfferingBird object
                    #retrieve that OfferingBird object's associated OfferingBirdItems object
#
class OfferingBirdLocations:
    def __init__(self, location_name, locations_count):
        self.location_name = location_name
        self.locations_count = locations_count

    def get_locations_count(location_name):


class OfferingBirdItems:
    def __init__(self, offering_bird_item_name, probability, reputation_requirement):
        self.offering_bird_item_name = offering_bird_item_name #String
        self.probability = probability #Integer
        self.reputation_requirement = reputation_requirement #Integer
#

This is what I've got built out. But like for example, how would I get the locations_count number for each player_location there?

#

Because order of operations, you enter an area and the list of True and False is generated based on the OfferingBirdLocation object's location_count variable. So if we enter Wellspring Village and the OfferBirdLocation object where self.name == "Wellspring Village" has a self.location_count = 5, we'd get something like [True, False, False, True, False].

#

And then for each True in that bird_spawn_list variable, we'd generate a bird to go there and then generate the associated OfferingBird object's offering list.

#

Right? Does that make sense?

clear thorn
#

It might be simpler to generate a random number between 0 and the location count, and then get that many random birds from the list. Either way should work though.

regal adder
#

I figured doing it this way lets me use each False index as indicator of where the Trues are.

#

Otherwise how would you know which spots specifically were filled?

clear thorn
#

If it matters which ones are filled or not then yeah, that works just fine

#

Like if the individual locations in the location count of 5 have unique properties or considerations, then you want to keep track of them, so it makes sense. If it's just the number of total spawns and it doesn't matter where which bird goes, then you don't really need to keep track. At least as far as I see it with what you have

regal adder
#

Yes, that's what I'm planning for. Possibly adding different things to each location like spawn rate modifiers so one type of bird appears more frequently there or something.

#

So what would be the syntax for getting the location_count integer for the player_location in the generate_offering_bird_spawn_locations function?

#

Obviously not hard-coded to individual strings but I'm not sure how you'd write it to be dynamic.

clear thorn
#

The first thing would be to keep in mind that any functions inside a class are going to be specific to each instance of that class. Your function to generate spawn locations should probably not be tied to that class. Otherwise you'll be awkwardly calling bird.generate_offering_bird_spawn_locations() when it has nothing to do with the bird.

#

Similarly, to get the player location you'd be calling player.get_player_location(). Or even just player.location if you keep it as a property that gets updated when the player moves.

regal adder
#

Hm. So generate_offering_bird_spawn_locations should not be in a class at all?

#

That makes sense. Okay.

#

There will probably be multiple players so player.get_player_location for each Player object should be good I think.

clear thorn
# regal adder Obviously not hard-coded to individual strings but I'm not sure how you'd write ...

To make it dynamic would just be something like this. Whenever your game logic has the player move to a new location, you call player.update_player_location('somewhere'). That updates the location of the player object. Then whenever some other piece of code gets the location, it's returning wherever the player currently is

class Player:
    def __init__(self, player_name, location_name):
        self.player_name = player_name
        self.location_name = location_name
        
    def get_player_location(self):
        #return self.location_name
        return self.location_name
    def update_player_location(self,new_location):
        self.location_name = new_location
clear thorn
regal adder
#

Ah okay. This makes sense to me.

#

So then we need to call get_player_location on the created player object.

#
player1 = Player("Shay", "Wellspring Village")
#

But how do we do that dynamically here?

def generate_offering_bird_spawn_locations():
    bird_spawn_list = []
    player_location = get_player_location()
    if player_location == "Wellspring Village":
        #Get the locations_count number for that location from the associated OfferingBirdLocation object.
        for i in range(0, #locations_count)
        bird_spawn_list.append(random.choice([True, False]))
            #for each True in the bird_spawn_list
                #generate an OfferingBird object
                #retrieve that OfferingBird object's associated OfferingBirdItems object
#

So that I'm not hard coding which player we're talking about?

clear thorn
#

That's going to depend on your game loop

#

Whatever logic is handling how your players submit inputs, how those inputs are processed, etc. That's going to be what calls these functions.

#

That's also when it would pass along which player it's updating

regal adder
#

Okay so we'd need to do something like player.player_location and just player will be set elsewhere.

#

And then I'd need to prepopulate the OfferingBirdLocations right?

clear thorn
#

Right. You know you'll be passing a player object and what properties it's going to have, which is all you need to write this logic for now.

regal adder
#
if __name__ == "__main__":
    player_1 = Player("Shay", "Wellspring Village")
    player_2 = Player("Neoncamouflage", "Wellspring Village")
    offering_bird_location_1 = OfferingBirdLocation("Wellspring Village", 5)
#

Okay so we've got this as prepopulated data.

#

And then in the class we should have something like this right?

#
class OfferingBirdLocation:
    def __init__(self, location_name, location_count):
        self.location_name = location_name
        self.location_count = location_count

    def get_location_name():
        return self.location_name

    def get_location_count():
        return self.location_count
clear thorn
#

Yeah, that would work. Then you'd make all the locations just like the birds and do whatever you need with them.

regal adder
#

Why does it say self is undefined for the bottom 2 functions?

clear thorn
#

You forgot to pass it as a parameter. The functions don't know what self is

#

def get_location_name(self)

regal adder
#

Oh oops. Thank you.

#

Okay so then how do I get the location_count for the OfferingBirdLocation where the location_name matches the Player location_name?

#

I'll repaste it for you so it's easier to follow.

clear thorn
#

First thing, you'll want to pass the player as a parameter. Not hardcode it

#

Because you want the main loop to be able to call generate_offering_bird_spawn_locations(player)

#

You'll also want to pass in the list of locations so you can loop through it

#

And check which matches the player location

regal adder
#

Oh dang, you're correct.

#

Okay one second.

#
def generate_offering_bird_spawn_locations(player, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player.get_location() == offering_bird_location_1.get_location_name:
            offering_bird_location_count = offering_bird_location_1.get_offering_bird_location_count
        #Get the locations_count number for that location from the associated OfferingBirdLocation object.
        for i in range(0, locations_count)
        bird_spawn_list.append(random.choice([True, False]))
            #for each True in the bird_spawn_list
                #generate an OfferingBird object
                #retrieve that OfferingBird object's associated OfferingBirdItems object
#

And then the location list.

#

And that would be me hard-coding all the OfferingBirdLocation objects and then putting that into a list, correct?

clear thorn
#

Yeah, sorry, had to run through it again. Just like we have the list of bird objects for each one, you'll have a list of location objects

regal adder
#

No worries at all. It's a lot.

#

Okay, I've got 3 basic locations.

#
if __name__ == "__main__":
    player_1 = Player("Shay", "Wellspring Village")
    player_2 = Player("Neoncamouflage", "Wellspring Village")
    offering_bird_location_1 = OfferingBirdLocation("Wellspring Village", 5)
    offering_bird_location_2 = OfferingBirdLocation("Location 2", 3)
    offering_bird_location_3 = OfferingBirdLocation("Location 3", 8)
    offering_bird_location_list = [offering_bird_location_1, offering_bird_location_2, offering_bird_location_3]
clear thorn
#

Definitely still recommend doing that dynamically, but it'll work lol

regal adder
#
def generate_offering_bird_spawn_locations(player, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player.get_location() == offering_bird_location_1.get_location_name:
            offering_bird_location_count = offering_bird_location_1.get_offering_bird_location_count
            for i in range(0, offering_bird_location_count):
                bird_spawn_list.append(random.choice([True, False]))
                for i in range(0, bird_spawn_list):
                    if bird_spawn_list[i] == True:
                        #generate an OfferingBird object
                        #retrieve that OfferingBird object's associated OfferingBirdItems object
regal adder
#

Can you elaborate a bit more on the dynamic object creation?

clear thorn
# regal adder I still don't quite get how you'd do that though.

You just make one list of all the details. So for the current locations it'd look like this:

location_data = [
    ('Wellspring Village',5),
    ('Location 2',3),
    ('Location 3',8)
  ]

Then we use one loop and make all the objects at once, in one list:

all_locations = []
for location in location_data:
  name, count = location #This breaks the tuple's contents up and assigns each to a variable
  all_locations.append(OfferingBirdLocation(name,count)) #Create the location with the data and add it to the list
#

Then anytime you need to search through locations, you just pass the all_locations list. If you need to make new locations, you add another tuple of data to location_data and don't have to worry about updating and making new variables everywhere else

regal adder
#

Hm.

#

So then I can still search through location_data to find a specific location_name for example?

clear thorn
#

You could, but at that point there's no reason to be making them into objects. I'm assuming the locations will have more properties, methods, data that changes in each that you'd need to keep track of.

#

If not, and if it's pretty much always going to just be the name and the count, nothing that changes or updates or whatever. Then just use the data list from the get go and skip making them objects.

#

If you go that route, you can even make it a dictionary for extra convenience. Something like:

location_data = {
    "Wellspring Village":5,
    "Location 2":3,
    "Location 3":8
  }

And you can just pull count with location_data.get(player.location_name)

regal adder
#

I want to do the object way just so I can learn more I think.

clear thorn
#

They're all options, no real wrong way, just whatever makes sense to you

#

That'll work

regal adder
#

Okay I understand now. One moment while I do that for all the objects.

#
#Dynamically creates a list of all Player objects.
    player_data = [
        ("Shay", "Wellspring Village"),
        ("Neoncamouflage", "Wellspring Village")]

    all_players = []
    for player in player_data:
        player_name, player_location = player #This breaks the tuple's contents up and assigns each to a variable
        all_players.append(Player(player_name, player_location)) #Create the location with the data and add it to the list

    #Dynamically creates a list of all OfferingBird objects.
    offering_bird_list = [
        ("Courigeon", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village", "Location 2", "Location 3"])
        ("Baublekaw", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village"]),
        ("Outflit", 80, (datetime.time(22,0,0), datetime.time(4,0,0)), ["Wellspring Village"]),
        ("Hautehoot", 80, (datetime.time(22,0,0), datetime.time(4,0,0)), ["Wellspring Village"]),
        ("Vogueowl", 80, (datetime.time(22,0,0), datetime.time(4,0,0)), ["Wellspring Village"])
    ]
    all_offering_birds = []
    for offering_bird in offering_bird_list:
        player_name, player_location = player #This breaks the tuple's contents up and assigns each to a variable
        all_players.append(Player(player_name, player_location)) #Create the location with the data and add it to the list

    #Dynamically creates a list of all OfferingBirdLocation objects.
    offering_bird_location_data = [
        ("Wellspring Village", "5"),
        ("Location 2", "3"),
        ("Location 3", "8")]

    all_offering_bird_locations = []
    for offering_bird_location in offering_bird_location_data:
        player_name, player_location = player #This breaks the tuple's contents up and assigns each to a variable
        all_players.append(Player(player_name, player_location)) 
#

Much more difficult to keep track of 3 of these.

#

Have to fix my comments too.

#

Phew. Okay, that was hard.

#

So then we have to use these in the generate_offering_bird_spawn_locations function.

clear thorn
#

Probably want to change the loops to match:

for offering_bird_location in offering_bird_location_data:
        player_name, player_location = player
#

Right now they're all player

regal adder
#

Yup I just saw that. ๐Ÿ˜„

#

Thank you for doublechecking my work.

clear thorn
#

But then yeah. For the spawn locations it'll just be generate_offering_bird_spawn_locations(player,all_offering_bird_locations). Then the function checks the locations for which name matches where the player is, and uses that location's count to make your True/False list

regal adder
#

Hm.

#

I'm getting an error trying to initialize the birds.

#
PS C:\Users\Shay\Documents\Godot\3DActionRPGRemasteredTutorial\3DActionRPGRemasteredPractice> & C:/Users/Shay/AppData/Local/Programs/Python/Python311/python.exe c:/Users/Shay/Documents/MyCode/MyPythonCode/NotPokemonBirdTrades.py
c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py:157: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
  ("Courigeon", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village", "Location 2", "Location 3"])
DATETIME 2024-12-12 15:26:11.863426 TIME 15:26:11.863426
Traceback (most recent call last):
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 157, in <module>
    ("Courigeon", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village", "Location 2", "Location 3"])
                       ^^^^^^^^^^^^^^^^^^^^
TypeError: descriptor 'time' for 'datetime.datetime' objects doesn't apply to a 'int' object
#

I'm only seeing examples for creating a datetime.time object where you have to put in year, month, and day too.

#

(class) datetime
datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])

The year, month and day arguments are required. tzinfo may be None, or an instance of a tzinfo subclass. The remaining arguments may be ints.

#

But all I care about is time of day. ๐Ÿค”

clear thorn
#

The datetime module has different object types. The most common is datetime. There's also date and time. In this case, we only want the time.

#

(datetime.time(4,0,0), datetime.time(20,0,0))
These are tupled together

regal adder
#

Yeah, that way I could keep them as one variable and just do [0] or [1] depending on if I want start or end time.

regal adder
clear thorn
regal adder
#

I tried that before and it didn't work.

#

Hmmm. Let me try again.

#

So you're saying just do ```py
import datetime

clear thorn
#

Right, that will let you use any of the objects. datetime.time(), datetime.date(), or datetime.datetime()

#

from datetime import datetime specifically imports the datetime object type, and not the other two

regal adder
#

AttributeError: 'datetime.time' object has no attribute 'time'

clear thorn
#

What's your full code lol

regal adder
#
import datetime
import random
current_datetime = datetime.time()
current_time = current_datetime.time()
print(f'DATETIME {current_datetime} TIME {current_time}')
clear thorn
#

Ah, gotcha, this bit is specific to trying to get the current time

current_time = current_datetime.time()```

You're getting the time. Then trying to get the time from the time. For this, you'll do:

current_datetime = datetime.datetime.now()
current_time = current_datetime.time()

#

Just because time() by itself doesn't have anything like now() to get the current one. You have to go through datetime first

#

Sorry about the confusion

regal adder
#

Ah okay. That seems really odd.

#

You'd think they'd have one that just gives you the time.

clear thorn
#

Some better way might exist and I just don't know about it, that's certainly possible lol

regal adder
#

๐Ÿ˜„ How do we fix the ones in the objects then?

#
("Trinketalon", 80, (datetime.time(4,0,0), datetime.time(20,0,0)), ["Wellspring Village"]),
clear thorn
#

Those are fine, it's just mad that the two are tupled together

#

The bird class, last I saw, expects them separate

#

If you want them as one value then you can change the tuple to an array and it should chill out

regal adder
#
class OfferingBird:
    def __init__(self, offering_bird_name, probability, spawn_time_range, locations_list, offering_list):
        self.offering_bird_name = offering_bird_name #String
        self.probability = probability #Integer
        self.spawn_time_range = spawn_time_range #Tuple
        self.locations_list = locations_list #List of Tuples
        self.items_list = offering_list #Object
#

What is the difference between a tuple and an array?

#

It's now just made that a tuple object is not callable.

clear thorn
#

Oh, whoop, the first element is missing a comma

#

In the bird list, that's all

clear thorn
regal adder
#

๐Ÿ˜„ Of course I missed a comma.

#

Ah okay. So arrays are the same as lists?

clear thorn
#

Arrays are what every other language calls a list, lol

regal adder
#

Oohhh. Gotcha! ๐Ÿ˜„

#

Okay so then back to this.

#
def generate_offering_bird_spawn_locations(player, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player.get_location() == offering_bird_location.get_location_name:
            offering_bird_location_count = offering_bird_location.get_offering_bird_location_count
            for i in range(0, offering_bird_location_count):
                bird_spawn_list.append(random.choice([True, False]))
                print(f'THIS IS IT {bird_spawn_list}')
                for i in range(0, bird_spawn_list):
                    if bird_spawn_list[i] == True:
                        bird_spawn_list[i] = True
                        #generate an OfferingBird object
                        #retrieve that OfferingBird object's associated OfferingBirdItems object
clear thorn
#

Yep, now you should be all set for this.

#

Though you've got some bugs, like missing some parentheses on function calls: offering_bird_location.get_offering_bird_location_count. So you'll probably have a few syntax errors to work through

regal adder
#

Alright, fixed that.

#

How can I call this so I can test it?

#
generate_offering_bird_spawn_locations(player, offering_bird_location_list)
#

So I need to dynamically get those two arguments.

#

Which means I need a get_player_name function.

clear thorn
#

You can make one if you want. Or if you're looping through the players, then just player.player_name. Like this:

for player in all_players:
    generate_offering_bird_spawn_locations(player.player_name, offering_bird_location_list)
#

or wait, no

#

Why do you need the name? lol

regal adder
#

Because isn't that how we tell whose location where's getting in player.get_location?

#

Wait no.

#

That takes no arguments.

clear thorn
#

Yep, because that function is specific to each player instance, since it's inside the class

regal adder
#

We need the player object.

#

So how do we select a player object?

clear thorn
#

That goes back to how your main game loop will work. The simplest way to test right now is just to loop through all your players and do a thing for each

regal adder
#

Hm.

#

Well let's start with player_list[0] for now I suppose so I can test the bird generation.

clear thorn
#

That works too

regal adder
#
generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list[0])
clear thorn
#

offering_bird_location_list[0] your function wants the whole list, I believe.

#

Because it's checking which one your player is at

regal adder
#

Oh yes. You are correct.

#

One moment, I forgot to remove the second tier of rarity from the item list so I've got to fix that.

#

So if we have item_name, probability, and reputation_requirement as item variables, what would be the best way to say that "X item can only come from Y offering bird"?

#

Probably just have to add another variable for items and birds I guess.

#

Hm. Actually no. I could do one list variable for items and just have that be a list of all the birds that can drop that item.

#

And that's much easier to change.

clear thorn
#

If you want it that specific, X item from Y bird, then yeah you'll need probably a property on the birds that contains their items. If you want something that goes by probability or such, then you can just compare that with each of the birds

#

Yep, that works

regal adder
#

Okay back to the important stuff.

#
def generate_offering_bird_spawn_locations(player_name, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player_name.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player_name.get_location() == offering_bird_location.get_location_name():
            offering_bird_location_count = offering_bird_location.get_offering_bird_location_count
            for i in range(0, offering_bird_location_count):
                bird_spawn_list.append(random.choice([True, False]))
                print(f'THIS IS IT {bird_spawn_list}')
                for i in range(0, bird_spawn_list):
                    if bird_spawn_list[i] == True:
                        bird_spawn_list[i] = True
                        #generate an OfferingBird object
                        #retrieve that OfferingBird object's associated OfferingBirdItems object
#

I should put the current time inside Player objects too.

clear thorn
#

Is that specific to each player?

regal adder
#

Timezones, so yeah.

clear thorn
#

Hm, that's fair

regal adder
#

So then if we have a True value, we need to generate a bird.

clear thorn
#

Though it'd probably be better to save their timezone instead. Because once you set the player's time to the current time and it ticks over a minute, that time property is no longer accurate. You have to get it agan.

regal adder
#

Hm. How would we do that?

#

Or would you just run the get_time every minute?

clear thorn
#

Not every minute, just in those functions that need a current time.

regal adder
#

Well that would be every minute.

#

Everything will require current time.

#

Going to have lots of time-based events and all that.

clear thorn
#

Ah. For the moment I recommend just grabbing the current time where you need it. Timezones make things...messy

#

So that's going to be its own can of worms to debug and get working lol

#

Save it for after you've got your structure figured out

regal adder
#

๐Ÿ˜„ Gotcha! Will do. Let's get the bird functions working.

#

The time thing is weirding me out so we can finish that later.

#
    for i in range(0, offering_bird_location_count):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'method' object cannot be interpreted as an integer
clear thorn
#

Yep. Easy enough to expand what you have later on to also include a check for the time

#

So that means it wants an integer but found a method instead, which is a function that belongs to a class

regal adder
#

Oops I forgot the ().

clear thorn
#

You'll see that when you forget parentheses. Instead of calling a function, you directly assign it

#

Yep

regal adder
#

It's saying it's a string though.

#

Oh because it is.

#

I'm dumb.

#
    for i in range(0, bird_spawn_list):
             ^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'list' object cannot be interpreted as an integer
#

Length.

clear thorn
#

Yep lol

regal adder
#

I'm learning, I swear.

clear thorn
#

Classic part of programming. "Ok, it should all work now" and then you have to run it 14 times as it yells about all the little things you forgot

regal adder
#

You can see it in real time.

#

So true.

#

Okay so now.

#

How do I call the start and end times there?

#
def generate_offering_bird_spawn_locations(player_name, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player_name.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player_name.get_location() == offering_bird_location.get_location_name():
            offering_bird_location_count = offering_bird_location.get_offering_bird_location_count()
            print(f'AWAWAWA {offering_bird_location_count}')
            for i in range(0, offering_bird_location_count):
                bird_spawn_list.append(random.choice([True, False]))
                print(f'THIS IS IT {bird_spawn_list}')
                for i in range(0, len(bird_spawn_list)):
                    if bird_spawn_list[i] == True:
                        bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if start_time < current_time < end_time], weights=[i[1] for i in offering_bird_list], k=1)[0]
                        #generate an OfferingBird object
                        #retrieve that OfferingBird object's associated OfferingBirdItems object
clear thorn
#

So you either need to return the list of bird spawn locations, if that's all this function is supposed to provide, and then call another function or run through the logic to assign those birds. Or you need to pass the list of birds into this function so you can use it

regal adder
#

Probably do a generate_offering_bird_spawn function instead and it send the returned spawn locations to it I think.

#

Or would it make more sense as one function in your opinion?

clear thorn
#

Either can work. It's best to separate them if the two actions, generating a spawn list and getting birds based on a spawn list, might ever happen separately.

#

If they'll only ever happen at the same time, as you're doing it now, then it can be one. I would change the function name in that case though, so it's more accurate

#

Probably default to the first one so you're not finding yourself writing half this function over again if you run into a situation where you do need that logic separated out

regal adder
#

They should only ever happen at the same time.

#

The whole bird system will only ever work together.

clear thorn
#

You say that now ๐Ÿ˜›

regal adder
#

Yeah, that's a fair point.

#

Okay, so we'll return the bird_spawn_list.

#
def generate_offering_bird_spawn_locations(player_name, offering_bird_location_list):
    bird_spawn_list = []
    player_location = player_name.get_location()
    for offering_bird_location in offering_bird_location_list:
        if player_name.get_location() == offering_bird_location.get_location_name():
            offering_bird_location_count = offering_bird_location.get_offering_bird_location_count()
            for i in range(0, offering_bird_location_count):
                bird_spawn_list.append(random.choice([True, False]))
            return bird_spawn_list
clear thorn
#

Honestly if you keep this project going long term, especially as you learn more, you'll probably wind up rewriting a good portion of this. Maybe all of it lol

#

Just how it goes

regal adder
#

Hopefully I learn how to do it too. ๐Ÿ˜„

#

Okay so then return bird_spawn list and then put the output into generate_offering_bird_spawns.

clear thorn
#

Yep

regal adder
#

Wait, it says return's in the wrong spot?

#

Oh that's right. Need to remove more of it.

#
def generate_bird_spawns(bird_spawn_list, offering_bird_list):
    for i in range(0, len(bird_spawn_list)):
        if bird_spawn_list[i] == True:
            bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if start_time < current_time < end_time], weights=[i[1] for i in offering_bird_list], k=1)[0]
    #generate an OfferingBird object
    #retrieve that OfferingBird object's associated OfferingBirdItems object
clear thorn
#

Looks good, you'll need to get the current time if you want to do that check right now though

regal adder
#

Hmmm. Which comes from the player.

#

Also need get functions for start and end time.

clear thorn
#

I don't think those need a whole function

regal adder
#

?

#

Don't you have to do a function to get each variable out of an object?

clear thorn
#

Your list is full of bird objects, so you can just directly reference the property like this: i.spawn_time_range[0] < current_time < i.spawn_time_range[1]

#

Since you're looping through each bird with i

regal adder
#

Ohhhh.

#

I already made the get functions but that is good to know!

#
def generate_bird_spawns(bird_spawn_list, offering_bird_list):
    for i in range(0, len(bird_spawn_list)):
        if bird_spawn_list[i] == True:
            bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if 
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()], 
            weights=[i[1] for i in offering_bird_list], k=1)[0]
clear thorn
#

That'll work too

#

Using getters and setters, functions specifically to set or get a variable, is generally the more robust way to go about it. If you wind up changing formats or structure later on, it can save a lot of time by not needing to go rewrite every single place you reference the property

regal adder
#

Ah, okay.

#

I'll be robust then!

#
generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
#

So this should run both functions.

clear thorn
#

That will, yes

regal adder
#

Hm...

    i.get_spawn_time_start() < current_time < i.get_spawn_time_end()],
    ^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get_spawn_time_start'
clear thorn
#

hmm

regal adder
#

i is 0?

#
def generate_bird_spawns(bird_spawn_list, offering_bird_list):
    for i in range(0, len(bird_spawn_list)):
        if bird_spawn_list[i] == True:
            print(f'AAHAHA {i}')
            bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if 
            offering_bird_list[i].get_spawn_time_start() < current_time < offering_bird_list[i].get_spawn_time_end()], 
            weights=[i[1] for i in offering_bird_list], k=1)[0]
        print(f'BIRD SPAWNS {bird_spawn_list}')
#

I believe it should be this.

#

Indexing with i.

clear thorn
#

for i in offering_bird_list this loops through the elements, not indexes

#

i[0] this is taking the first element of that element, which should make it freak out if it's an object

#

Is offering_bird_list the list of bird data, or the list of birds

#

I think it's the list of bird data

regal adder
#

List of objects.

#
#Dynamically creates a list of all OfferingBird objects.
    offering_bird_data = [
        ("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2", "Location 3"]),
        ("Baublekaw", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village"]),
        ("Outflit", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Hautehoot", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Vogueowl", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"])
    ]
    offering_bird_list = []
    for offering_bird in offering_bird_list:
        offering_bird_name, probability, spawn_time_range, locations_list, offering_list, player_location = offering_bird #This breaks the tuple's contents up and assigns each to a variable
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_range, locations_list, offering_list))
clear thorn
#

That doesn't look right

#

for offering_bird in offering_bird_list:

#

That should be offering_bird_data

#

But that means the list should be empty, odd

regal adder
#

Ah, you are correct.

#

OKAY. Fixed that.

#

Now I need to build out the item lists for each of those birds too so I can build them into the bird objects.

#
#Dynamically creates a list of all OfferingBirdItem objects.
    offering_bird_item_data = [
        ("Shiny Pebble", 50, 0, ["Courigeon"]),
        ("Tumbled Agate", 40, 5, ["Courigeon"]), 
        ("Lost Mail", 10, 20, ["Courigeon"]),
        ("Rations", 50, 0, ["Courigeon"]), 
        ("Wrist Wraps - Clean", 40, 5, ["Courigeon"]), 
        ("Wrist - Wraps - Bloodied", 10, 20, ["Courigeon"]),
        ("Running Shoes", 85, 0, ["Courigeon"]), 
        ("Fingerless Gloves - Black", 5, 10, ["Courigeon"]), 
        ("Fur-collared Jacket", 5, 85, ["Courigeon"]), 
        ("Wellspring Village Pendant", 5, 90, ["Courigeon"])]

    offering_bird_item_list = []
    for offering_bird_item in offering_bird_item_data:
        item_name, probability, reputation_requirement, offering_bird_list = offering_bird_item #This breaks the tuple's contents up and assigns each to a variable
        offering_bird_item_list.append(OfferingBirdItem(item_name, probability, reputation_requirement, offering_bird_list)) #Create the location with the data and add it to the list

    generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
sinful canyon
#

hc

regal adder
#

So how do I look at the list at the end there and make it so that based on the birds in that list, it builds out an item list for that bird of only ones where their name was in the associated birds list?

#
#Dynamically creates a list of all OfferingBird objects.
    offering_bird_data = [
        ("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2", "Location 3"]),
        ("Baublekaw", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village"]),
        ("Outflit", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Hautehoot", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Vogueowl", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"])]

    offering_bird_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_range, locations_list, offering_list, player_location = offering_bird #This breaks the tuple's contents up and assigns each to a variable
    for offering_bird_item in offering_bird_item_list:
        if offering_bird_name in offering_bird_item_list:
            
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_range, locations_list, offering_list)) #Create the location with the data and add it to the list
clear thorn
#

Are you wanting this item list generated after generate_bird_spawns?

regal adder
#

Yes.

#

But the item list is required to build the OfferingBird objects first.

clear thorn
#

Oh you want the items as a property on the bird. So like the Gourigeon bird object would have a list of its items

regal adder
#

Correct!

#
#Dynamically creates a list of all OfferingBird objects.
    offering_bird_data = [
        ("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2", "Location 3"]),
        ("Baublekaw", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village"]),
        ("Outflit", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Hautehoot", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Vogueowl", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"])]

    offering_bird_list = []
    offering_bird_item_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_range, locations_list, offering_list, player_location = offering_bird #This breaks the tuple's contents up and assigns each to a variable
    for offering_bird_item in offering_bird_item_list:
        if offering_bird_name in offering_bird_item_list[3]:
            offering_bird_item_list.append(offering_bird_item)
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_range, locations_list, offering_list)) #Create the location with the data and add it to the list
#

I think I'm close here.

clear thorn
#

Pretty much there

#

You'll want to scoot the second for loop over so it's inside the first one. Because you want to loop over every item, and do it for every bird

regal adder
#

So like this?

#
#Dynamically creates a list of all OfferingBird objects.
    offering_bird_data = [
        ("Courigeon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2", "Location 3"]),
        ("Baublekaw", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, datetime.time(4,0,0), datetime.time(20,0,0), ["Wellspring Village"]),
        ("Outflit", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Hautehoot", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Vogueowl", 80, datetime.time(22,0,0), datetime.time(4,0,0), ["Wellspring Village"])]

    offering_bird_list = []
    offering_bird_item_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_range, locations_list, offering_list, player_location = offering_bird #This breaks the tuple's contents up and assigns each to a variable
        for offering_bird_item in offering_bird_item_list:
            if offering_bird_name in offering_bird_item_list[3]:
                offering_bird_item_list.append(offering_bird_item)
            offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_range, locations_list, offering_list)) #Create the location with the data and add it to the list
clear thorn
#

Yep

regal adder
#

Okay, gotcha.

#
    offering_bird_list[i].get_spawn_time_start() < current_time < offering_bird_list[i].get_spawn_time_end()],
    ~~~~~~~~~~~~~~~~~~^^^
TypeError: list indices must be integers or slices, not str
#

My fix did not work here.

clear thorn
#

Print out offering_bird_list before that and see exactly what it is

#

This still doesn't make sense

#

oh wait

#

If it's still for i in then that isn't an index

#

i is the bird

#

or the data item, whichever that list is

regal adder
#
OFFERING BIRD LIST ['Courigeon'] I 0
OFFERING BIRD LIST ['Courigeon'] I 1
#

Looks like bird name value.

clear thorn
#

Well that's not right

regal adder
#

Nope, we need the OfferingBird object.

clear thorn
#

Go check where you're calling that function and see what you're passing it

#

At some point something got mixed up

regal adder
#
generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
clear thorn
#

odd

#

Mind dropping the full thing again lol

#

I'm not sure what's gone astray with just the snippets

regal adder
#

Yup!

#

Think I messed up something with adding the item list to the birds.

#

Offering_bird_item_list is indeed the full list of item objects.

clear thorn
#

Definitely different errors on that

    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, offering_list = offering_bird

This needs offering_list removed, since that isn't part of the bird data

regal adder
#

Yeah I caught that.

#
 offering_bird_list = []
    offering_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list = offering_bird #This breaks the tuple's contents up and assigns each to a variable
        for offering_bird_item in offering_bird_item_list:
            print(f'OFFERING BIRD ITEM LIST 3 {offering_bird_item_list}')
            if offering_bird_name in offering_bird_item_list[3]:
                offering_bird_item_list.append(offering_bird_item)
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, offering_list)) #Create the location with the data and add it to the list

    print(f'OFFERING BIRD LIST2 {offering_bird_list}')
    generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
    
#

I need to index into the items in offering_bird_item_list before getting the 3rd element.

clear thorn
#

Oh the last line, appending the bird to the offering bird list, needs to back up out of that second for loop

regal adder
#

Gotcha.

#
if offering_bird_name in offering_bird_item_list[3]:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: argument of type 'OfferingBirdItem' is not iterable
#

OFFERING BIRD ITEM LIST 3 [<main.OfferingBirdItem object at 0x000001E951463CD0>, <main.OfferingBirdItem object at 0x000001E951463D10>, <main.OfferingBirdItem object
at 0x000001E951463D50>, <main.OfferingBirdItem object at 0x000001E951463D90>, <main.OfferingBirdItem object at 0x000001E951463DD0>, <main.OfferingBirdItem object at
0x000001E951463E50>, <main.OfferingBirdItem object at 0x000001E951463E90>, <main.OfferingBirdItem object at 0x000001E951463ED0>, <main.OfferingBirdItem object at 0x000001E951463F10>, <main.OfferingBirdItem object at 0x000001E951463E10>]

clear thorn
#

So for that it looks like you've already turned those items into objects

#

Meaning you need to access their properties, not indexes

regal adder
#

Ohhhhh.

#
if offering_bird_name in offering_bird_item_list.get_offering_bird_list():
clear thorn
#

for offering_bird_item in offering_bird_item_list:
This makes offering_bird_item the item object as it loops through the list

#

You need to call any functions on that, not the whole list

regal adder
#

I am confused.

regal adder
#

That is what we have already.

clear thorn
#

You're calling a function on the list

#

Not the item

regal adder
#

Oh we do it twice.

#

Hmmm.

clear thorn
#

You might have it twice, but for that line specifically, it should be offering_bird_item, not offering_bird_item_list

#

Because only the item has that function to call

regal adder
#

Okay please show me what should be the current version.

#

I may have messed up somewhere.

clear thorn
#
    bird_specific_item_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list = offering_bird

        for offering_bird_item in offering_bird_item_list: #Loop through each item object in the list
            if offering_bird_name in offering_bird_item.get_offering_bird_list(): #Call the get function on the item to get the list of birds, and see if our bird is in it
                bird_specific_item_list.append(offering_bird_item) #If so, add it to our bird specific item list
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, bird_specific_item_list)) #Create the bird with all the data, and our item list
#

I made a new variable for our bird specific items, because they were getting reused in the wrong places

#

Now that will break up the data into variables, then for each item it will call the function to get the bird list from that item object. If the bird is in that list, it adds it to the bird specific item list. Which is then used at the end to make the bird object

regal adder
#

Very good call on the new variable. I was very confused.

clear thorn
#

Yeah, that'll happen when there's too many similar ones

regal adder
#

Okay so that I beleive should be fixed.

#

Then we have

line 93, in generate_bird_spawns
    bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 94, in <listcomp>
    i.get_spawn_time_start() < current_time < i.get_spawn_time_end()],
    ^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'get_spawn_time_start'
clear thorn
#

For that one, i is still the bird name. It's getting passed the data for the function somehow I believe. Go to the start of that function, as the first step, and print out the list to see what it is

regal adder
#

Gotcha.

#
def generate_bird_spawns(bird_spawn_list, offering_bird_list):
    for i in range(0, len(bird_spawn_list)):
        print(f'OFFERING BIRD LIST {offering_bird_list} I {i}')
        if bird_spawn_list[i] == True:
            bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if 
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()], 
            weights=[i[1] for i in offering_bird_list], k=1)[0]
    print(f'BIRD SPAWNS {bird_spawn_list}')
#
OFFERING BIRD LIST ['Courigeon', <__main__.OfferingBird object at 0x0000012C4B8E01D0>, <__main__.OfferingBird object at 0x0000012C4B8E0250>, <__main__.OfferingBird object at 0x0000012C4B8E0290>, <__main__.OfferingBird object at 0x0000012C4B8E02D0>, <__main__.OfferingBird object at 0x0000012C4B8E0310>, <__main__.OfferingBird object at 0x0000012C4B8E0350>] I 0
#

That's not quite right.

#

How did that get in there?

clear thorn
#

lol, nope

#

Try printing out the list right after it gets made, is it getting inserted there?

#

Or in another function

regal adder
#
 bird_specific_item_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list = offering_bird
        print(f'WOWOWOWOW {bird_specific_item_list}\n')
        for offering_bird_item in offering_bird_item_list: #Loop through each item object in the list
            if offering_bird_name in offering_bird_item.get_offering_bird_list(): #Call the get function on the item to get the list of birds, and see if our bird is in it
                bird_specific_item_list.append(offering_bird_item) #If so, add it to our bird specific item list
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, bird_specific_item_list)) #Create the bird with all the data, and our item list
    generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
#

It's getting inserted right at the end.

clear thorn
#

Or at least, between the end and where it gets called in that function. Interesting

regal adder
#

Yeah.

#

How could that be?

#

The moment it hits generate_bird_spawns, that gets added.

#

But that doesn't make any sense.

clear thorn
#
    offering_bird_item_data = [
        ("Shiny Pebble", 50, 0, ["Courigeon"]),
        ("Tumbled Agate", 40, 5, ["Courigeon"]), 
        ("Lost Mail", 10, 20, ["Courigeon"]),
        ("Rations", 50, 0, ["Courigeon"]), 
        ("Wrist Wraps - Clean", 40, 5, ["Courigeon"]), 
        ("Wrist - Wraps - Bloodied", 10, 20, ["Courigeon"]),
        ("Running Shoes", 85, 0, ["Courigeon"]), 
        ("Fingerless Gloves - Black", 5, 10, ["Courigeon"]), 
        ("Fur-collared Jacket", 5, 85, ["Courigeon"]), 
        ("Wellspring Village Pendant", 5, 90, ["Courigeon"])]

    offering_bird_item_list = []
    for offering_bird_item in offering_bird_item_data:
        item_name, probability, reputation_requirement, offering_bird_list = offering_bird_item

No, it gets added before that

#

offering_bird_list gets reused as a variable name in the item data

#

And after that, contains the name of one bird

#

You can either do the good code practice thing and find a new variable to use for the item data, or just reset offering_bird_list = [] before you start looping through the bird data

regal adder
#

Let's do the good code practice.

#

Where do we need to change it though?

clear thorn
#

The part where you make the item list:

    offering_bird_item_list = []
    for offering_bird_item in offering_bird_item_data:
        item_name, probability, reputation_requirement, offering_bird_list = offering_bird_item #This breaks the tuple's contents up and assigns each to a variable
        offering_bird_item_list.append(OfferingBirdItem(item_name, probability, reputation_requirement, offering_bird_list)) #Create the location with the data and add it to the list

You change offering_bird_list to something else in both lines, because we need that variable later

regal adder
#

Ah okay.

clear thorn
#

Then down where you're making the bird list I think you'll still need to create the variable offering_bird_list = [] because I don't actually see it anywhere else

regal adder
#

offering_bird_carrier_list

#

Good point.

#

Okay, that change should now be made.

clear thorn
#

Nice, now to see how it else explodes

regal adder
#

๐Ÿ˜„

#
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 93, in generate_bird_spawns
    bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 93, in <listcomp>
    bird_spawn_list[i] = random.choices(population=[i[0] for i in offering_bird_list if
                                                    ~^^^
TypeError: 'OfferingBird' object is not subscriptable
#

Bare minimum I am learning a lot about how to find and fix bugs.

clear thorn
#

Oh, you're using an index on an object

#

Shouldn't need the [0] part

regal adder
#

So it should just be

 bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if 
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()], 
            weights=[i for i in offering_bird_list], k=1)
```?
clear thorn
#
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()]```
This part yes, because you're looping over the birds in the bird list and getting their spawn time starts and ends
#

weights=[i for i in offering_bird_list]
This part you'll need to get the weights

regal adder
#

Hm. Okay that makes sense but then it's saying this.

#
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 217, in <module>
    generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 93, in generate_bird_spawns
    bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Shay\AppData\Local\Programs\Python\Python311\Lib\random.py", line 495, in choices
    cum_weights = list(_accumulate(weights))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'OfferingBird' and 'OfferingBird'
#

I don't believe we're trying to add birds where it says we are.

clear thorn
#

It's mad about the weights

#

weights=[i for i in offering_bird_list] This part, where I said you need to get the weights ๐Ÿ˜›

#

i for i in offering_bird_list means you take each bird in the list and assign it to the first i. Since they're objects, now you need to get its probability property to use for the weight

regal adder
#

Oh hm.

#

What's the syntax for that then?

#

i.get_probability() for i in offering_bird_list?

clear thorn
#

Exactly

regal adder
#

I'm learning! ๐Ÿ˜„

#

Oh maybe not.

#

raise ValueError('The number of weights does not match the population')
ValueError: The number of weights does not match the population

clear thorn
#

XD

#

oh duh

#

if i.get_spawn_time_start() < current_time < i.get_spawn_time_end()

#

This bit. Is limiting the population

#

So it needs to limit the weights too

regal adder
#

Oh man. How do I do that?

clear thorn
#

Same way as it is in the first one

#

Just stick it on the end lol

regal adder
#

I was just about to say, don't tell me. ๐Ÿ˜„

#

Hm. Same error.

clear thorn
#

Oh?

#

What's the full thing you have now

regal adder
#
def generate_bird_spawns(bird_spawn_list, offering_bird_list):
    for i in range(0, len(bird_spawn_list)):
        if bird_spawn_list[i] == True:
            print(f'BIRD SPAWN LIST {bird_spawn_list}')
            bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if 
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()], 
            weights=[i for i in offering_bird_list if 
            i.get_spawn_time_start() < current_time < i.get_spawn_time_end()], k=1)
    print(f'BIRD SPAWNS {bird_spawn_list}')
clear thorn
#

Seems to run fine for me

regal adder
#

Really?

#

I get this.

Traceback (most recent call last):
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 216, in <module>
    generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list)
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 93, in generate_bird_spawns
    bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if i.get_spawn_time_start() < current_time < i.get_spawn_time_end()],
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Shay\AppData\Local\Programs\Python\Python311\Lib\random.py", line 495, in choices
    cum_weights = list(_accumulate(weights))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'OfferingBird' and 'OfferingBird'
clear thorn
#

oh, what

#

weights=[i for i in offering_bird_list if

#

That part got changed back

#

It's missing the function to get the probability

regal adder
#

Oh weird.

#

Woops.

#

Good catch!

#

BIRD SPAWNS [False, False, [<main.OfferingBird object at 0x000001CD08160310>], False, [<main.OfferingBird object at 0x000001CD08160310>]]

#

WOOOOOOOO!

#

It works! ๐Ÿ˜„

clear thorn
#

Ayoo

#

Very nice

regal adder
#

Okay, and then just the items.

#

But dinner is ready so I'll be back shortly! Thank you again so incredibly much for all your help!

#

Okay, I am back!

#
def generate_bird_items(item_list, player_reputation):
    bird_items_offered_count = get_bird_items_offered_count(player_reputation)
    available_items = []
    item_selection_list = []
    for item in item_list:
        if item[2] <= player_reputation:
            available_items.append(item)
    for i in range(0, min(bird_items_offered_count,len(available_items))):
        item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
        item_selection_list.append(item_selection)
        available_items = [item for item in available_items if item[0] != item_selection]
    return item_selection_list


def get_player_reputation(bird_species):
    if bird_species == "Courigon":
        player_reputation = 100
    elif bird_species == "Trinketalon" or "Baublekaw":
        player_reputation = 100
    elif bird_species == "Hautehoot" or "Vogueowl":
        player_reputation = 100
    return player_reputation

def get_bird_items_offered_count(player_reputation):
    if player_reputation == 100:
        return 4
    else:
        return player_reputation // 33 + 1
#

Okay so from generate_bird_items we return the bird_spawn_list which looks like this.
[False, False, [<main.OfferingBird object at 0x000001CD08160310>], False, [<main.OfferingBird object at 0x000001CD08160310>]]

#

So then we want to get the available items based on the player's reputation and the bird type.

#

So reputation should probably be a Player object variable.

#

Should reputation be across bird species, across locations, both, etc.?

regal adder
#

@clear thorn How would you write for bird in bird_spawn_list where bird != False?

#
def generate_bird_offers(player_name, bird_spawn_list):
    for bird in bird_spawn_list if bird != False:
        if bird.get_offering_bird_name in ["Courigeon"]:
            player_reputation = player_name.get_bird_reputation_common()
        if bird.get_offering_bird_name in ["Baublekaw", "Trinketalon"]:
            player_reputation = player_name.get_bird_reputation_uncommon()
        if bird.get_offering_bird_name in ["Outflit", "Hautehoot", "Vogueowl"]:
            player_reputation = player_name.get_bird_reputation_rare()
        for item in bird_spawn_list[i]:
            print(f'WOWOW {item}')
``` This is what I have so far.
clear thorn
clear thorn
# regal adder ```py def generate_bird_offers(player_name, bird_spawn_list): for bird in bi...

Probably just make a guard clause at the start of the loop. If bird is false then we continue to the next one

def generate_bird_offers(player_name, bird_spawn_list):
    for bird in bird_spawn_list:
        if not bird:
            continue
        if bird.get_offering_bird_name() in ["Courigeon"]:
            player_reputation = player_name.get_bird_reputation_common()
        if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
            player_reputation = player_name.get_bird_reputation_uncommon()
        if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
            player_reputation = player_name.get_bird_reputation_rare()
regal adder
#

And then apparently bird is a list item.

#
    if bird.get_offering_bird_name in ["Courigeon"]:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'get_offering_bird_name'
#

So I need to index.

#

Wait no.

#

They're both lists.

#

Wait no.

clear thorn
#

You're missing parentheses

#

But apparently that is a list lol

#

Oh hey yeah, they are lists

regal adder
#

()

clear thorn
#

[False, [<__main__.OfferingBird object at 0x000001513C3C3370>], False, False, [<__main__.OfferingBird object at 0x000001513C3C3370>]]

regal adder
#

Ah you found it first. ๐Ÿ˜„

clear thorn
#

Ah, random.choices() returns a list, even if it's only one item, right.

#

So you can just throw a [0] on the end of that, back in the generate_bird_spawns() function if you want

regal adder
#

Yup!

#
def generate_bird_offers(player_name, bird_spawn_list):
    for bird in bird_spawn_list:
        if bird:
            print(f'BIRD {bird.get_offering_bird_name()}')
            if bird.get_offering_bird_name() in ["Courigeon"]:
                player_reputation = player_name.get_bird_reputation_common()
                print("Common")
            if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
                player_reputation = player_name.get_bird_reputation_uncommon()
                print("Uncommon")
            if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
                player_reputation = player_name.get_bird_reputation_rare()
                print("Rare")
            get_bird_items_offered_count(player_reputation)
#

Okay so this is where I'm at.

#

Then we need to add the reputation.

#

Hm.

#

Okay my reputation math function was poor.

#

Need your thoughts on a good way to do this.

#
def get_bird_items_offered_count(player_reputation):
    if player_reputation == 100:
        return 4
    else:
        return player_reputation // 33 + 1
#

Maybe I should do it to a maximum of 5 actually.

#

Then each 25 reputation would unlock another trade window with 1 extra for 100.

#

Okay so how do I write this so that 0-24 returns 1, 25-50 returns 2, 51-75 returns 3, 76-99 returns 4, and 100 returns 5?

#

I feel like there's got to be a neat math way to do that instead of just comparisons and ranges.

clear thorn
#

player_reputation // 25 + 1 should do it

regal adder
#

Ah okay.

#

So I was right.

#

But I'd still need that top part for 100 specifically right?

#

No way to math around that?

clear thorn
#

100 // 25 will give 4

#

Plus 1 makes 5

regal adder
#

Wow I've been working on this too long. Good lord.

clear thorn
#

lmao

regal adder
#

Goobye basic mathematical skills.

#

Okay so this works perfectly then.

#
def get_bird_items_offered_count(player_reputation):
    return player_reputation // 25 + 1
clear thorn
#

Yep, that'll do it

regal adder
#

So then we need to get the list of items that bird can carry and the ones that have reputation requirements less than or equal to the players reputation with that bird rarity.

#
def generate_bird_offers(player_name, bird_spawn_list):
    for bird in bird_spawn_list:
        if bird:
            print(f'BIRD {bird.get_offering_bird_name()}')
            if bird.get_offering_bird_name() in ["Courigeon"]:
                player_reputation = player_name.get_bird_reputation_common()
                print("Common")
            if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
                player_reputation = player_name.get_bird_reputation_uncommon()
                print("Uncommon")
            if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
                player_reputation = player_name.get_bird_reputation_rare()
                print("Rare")
            print(f'ITEMS OFFERED COUNT {get_bird_items_offered_count(player_reputation)}')
#

Not really even sure how to start with that.

clear thorn
#

Well the birds already have their items as a property

#

So you just need to compare the reputation

regal adder
#

Hm.

#

So to get the offering list I do bird.get_offering_list() but then can I do .get_reputation_requirement() on top of that so like bird.get_offering_list().get_reputation_requirement()?

#

WAIT.

#

I know.

clear thorn
#

lol, I believe in you

regal adder
# clear thorn lol, I believe in you
def generate_bird_offers(player_name, bird_spawn_list):
    offerings_available = []
    offerings_displayed = []
    for bird in bird_spawn_list:
        if bird:
            print(f'BIRD {bird.get_offering_bird_name()}')
            if bird.get_offering_bird_name() in ["Courigeon"]:
                player_reputation = player_name.get_bird_reputation_common()
                print("Common")
            if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
                player_reputation = player_name.get_bird_reputation_uncommon()
                print("Uncommon")
            if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
                player_reputation = player_name.get_bird_reputation_rare()
                print("Rare")
            bird_offering_count = get_bird_offering_count(player_reputation)
            print(f'BIRD OFFERING LIST {bird.get_offering_list()}')
            for offering in bird.get_offering_list():
                if offering.get_reputation_requirement() <= player_reputation:
                    offerings_available.append(offering)
            for i in range(0, min(len(bird.get_offering_list), bird_offering_count)):
                offerings_displayed = random.choices(population=[i for i in offerings_available], weights=[i for i in offerings_available], k=1)[0]
#

Okay this is what I've got right now.

clear thorn
#

Because now you do actually want the list

#

Other than that, looks good at first glance

regal adder
#

Ah that's right.

#

I missed ().

#
    offerings_displayed = random.choices(population=[i for i in offerings_available], weights=[i for i in offerings_available], k=1)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Shay\AppData\Local\Programs\Python\Python311\Lib\random.py", line 495, in choices
    cum_weights = list(_accumulate(weights))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'OfferingBirdItem' and 'OfferingBirdItem'
#

We had this earlier because we were filtering the list and reducing the amount of weights and the birds differently or something.

#

But we're not filtering it here so we do we hae that?

clear thorn
#

Oh, no, so this is mad about the weights. It's trying to add i for each one

#

But i is an item*

#

So basically you need to get a property from i to weight it by, like you did with probability on the birds

#

Or decide whether you actually need weights at all, because that's an optional argument

regal adder
#

Oh I see.

#

Yes, we have weights for the items.

#

So weights=[i.get_probability() for i in offerings_available], k=1) right?

clear thorn
#

Yep. for i in offerings_available will loop through that list and assign each element to i, so you can call the function on it

regal adder
#

Think I did something very wrong somewhere because the offerings lists are like 50 deep.

clear thorn
#

ope

regal adder
#
def generate_bird_offers(player_name, bird_spawn_list):
    offerings_available = []
    offerings_displayed = []
    for bird in bird_spawn_list:
        if bird:
            print(f'BIRD {bird.get_offering_bird_name()}')
            if bird.get_offering_bird_name() in ["Courigeon"]:
                player_reputation = player_name.get_bird_reputation_common()
                print("Common")
            if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
                player_reputation = player_name.get_bird_reputation_uncommon()
                print("Uncommon")
            if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
                player_reputation = player_name.get_bird_reputation_rare()
                print("Rare")
            bird_offering_count = get_bird_offering_count(player_reputation)
            print(f'BIRD OFFERING LIST {bird.get_offering_list()}')
            for offering in bird.get_offering_list():
                if offering.get_reputation_requirement() <= player_reputation:
                    offerings_available.append(offering)
            print(f'OFFERINGS AVAILABLE {offerings_available}')
            for i in range(0, min(len(bird.get_offering_list()), bird_offering_count)):
                offering = random.choices(population=[i for i in offerings_available], weights=[i.get_probability() for i in offerings_available], k=1)
                offerings_displayed.append(offering)
                offerings_available = [offering for offering in offerings_available if offering not in offerings_displayed]
                print(f'AVAILABLE {offerings_available.get_item_name()} DISPLAYED {offerings_displayed}')
#

This is what I have.

clear thorn
#

That last for loop you probably don't need

regal adder
#

Well that's how you determine how many items they get though.

clear thorn
#

Ah, I see

regal adder
#

You make the offerings_available list of all the things that they could be given based on the bird and their reputation and then they get the lower of the two number of items available or their reputation item allowance.

clear thorn
#

offerings_available = [offering for offering in offerings_available if offering not in offerings_displayed]

This bit then, doesn't need to be executing every loop. Only once at the end, after the offerings_displayed are all gathered up.
You'll also want to stick the [0] back on the end of random.choices(), since you're not pulling the whole list at once like I thought you were

#

Though it's overwriting it, not appending, so it still shouldn't wind up with too many of them

regal adder
#

Isn't that bit the duplication prevention though?

#

Because you wouldn't want all 5 of your offers to be Shiny Pebbles.

#

Should only allow 1 of each item.

clear thorn
#

Oh that's where that came from

#

Sorry, hard to keep track of this XD

#

Oh you posted the link again, let me go run it here

#

Just spent a very confused five minutes tracking down a totally different bug because my local time flipped over and all the birds went invalid ๐Ÿคฆ

regal adder
#

๐Ÿ˜„

#

I spent a very confused 15 on the same bug.

#

I don't understand why it has so many objects.

clear thorn
#

OH

clear thorn
#
    bird_specific_item_list = []
    offering_bird_list = []
    for offering_bird in offering_bird_data:
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list = offering_bird
        for offering_bird_item in offering_bird_item_list: #Loop through each item object in the list
            if offering_bird_name in offering_bird_item.get_offering_bird_carrier_list(): #Call the get function on the item to get the list of birds, and see if our bird is in it
                bird_specific_item_list.append(offering_bird_item) #If so, add it to our bird specific item list
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, bird_specific_item_list)) #Create the bird with all the data, and our item list
    print(player_list)

#

bird_specific_item_list is never reset to empty for the next bird

#

So each one has the items of the last

regal adder
#

AH.

#

Okay that makes sense.

#

Where would we reset it here?

#

Probably just inside the first for right?

clear thorn
#

Yep

clear thorn
clear thorn
#

Right now it checks if i.get_spawn_time_start() < current_time < i.get_spawn_time_end(). Which works well if you want to see if your time is greater than say 6AM and less than 8PM. Doesn't work so well checking to see if your time is greater than 8PM and less than 6AM.

regal adder
#

Ohhhh.

#

How would we fix that though?

clear thorn
#

Remove nocturnal birds ๐Ÿ˜›

regal adder
#

Nooooo, night birds are cool. Gives you something to stay up late for.

clear thorn
#

Probably just an if statement before that line to see if it's in the nocturnal time range

#

If not, run the line that's there. If it is, run different logic.

regal adder
#

They won't all share the same ranges though.

clear thorn
#

Ah, welp

regal adder
#

So how would we go about that?

clear thorn
#

Not sure offhand

#

Probably some clever way to do that online

regal adder
#

Hm.

#

Okay well before that, I did this correct, yes?

#
offering_bird_list = []
    for offering_bird in offering_bird_data:
        bird_specific_item_list = []
        offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list = offering_bird
        for offering_bird_item in offering_bird_item_list: #Loop through each item object in the list
            if offering_bird_name in offering_bird_item.get_offering_bird_carrier_list(): #Call the get function on the item to get the list of birds, and see if our bird is in it
                bird_specific_item_list.append(offering_bird_item) #If so, add it to our bird specific item list
        offering_bird_list.append(OfferingBird(offering_bird_name, probability, spawn_time_start, spawn_time_end, locations_list, bird_specific_item_list)) #Create the bird with all the data, and our item list
    generate_bird_offers(player_list[0], generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list))
    

clear thorn
#

Looks like it, if the list is all you changed

regal adder
#

Yeah because we don't want to reset offering_bird_list.

#

Okay, fully comprehended.

#

Hmmmmm. Would 26,0,0 as a time be considered 2AM but also greater than 7PM?

clear thorn
#

I'm not sure that would be valid

regal adder
#

Hmmmmm.

clear thorn
#

You can try but I feel like datetime is gonna freak out about it

regal adder
#

Yeah and that wouldn't be a proper solution.

#

Something with absolute value?

#

No... ๐Ÿค”

#

I am very confused.

#

If all the ranges were the same difference from start to end you could maybe do something with addition to the low one if it's in front.

clear thorn
#
def is_hour_between(start, end, now):
    is_between = False

    is_between |= start <= now <= end
    is_between |= end < start and (start <= now or now <= end)

    return is_between
#

And the choices line in generate_bird_spawns() turns to this:

            bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if is_hour_between(i.get_spawn_time_start().hour, i.get_spawn_time_end().hour,current_time.hour)], 
            weights=[i.get_probability() for i in offering_bird_list if is_hour_between(i.get_spawn_time_start().hour, i.get_spawn_time_end().hour,current_time.hour)], k=1)[0]
regal adder
#

๐Ÿ˜„

clear thorn
#

I pretty much never see it used

regal adder
#

So in English, what is happening?

clear thorn
#

is_between is false, if now is between the start and end times, or if the end time is before the start time and now is greater than or equal to start, or less than or equal to end, then is_between becomes true

#

Basically it's just another way to do two if statements that would flip the return value to True

regal adder
#

Ah okay. Could you show me how the two if statement function would work too so I can relate them in my head?

#

And does this mean we could only set whole hours for the bird spawn times?

#

For certain events and stuff I think it would be cool to have minutes and seconds involved too.

clear thorn
clear thorn
#

You can make the logic fancier when you want to add those ๐Ÿ˜›

regal adder
#

What would be the method for adding them in?

clear thorn
#

Expanding the function to consider the minutes and seconds if the hours are equal should work

#

Then instead of passing it the hours when you call the function, you just pass it the whole time

regal adder
#

I guess I'm confused as to how it wouldn't work already if you just pass it the whole time.

clear thorn
#

Hm. Maybe it would lol

regal adder
#

Wouldn't just removing the .hour send the whole time?

clear thorn
#

Yep

regal adder
#

The comparison doesn't mention it anywhere so I think that would work?

clear thorn
#

Yeah, makes sense to me

regal adder
#

Hm.

#

Did you try it with the hours and you were able to get the nocturnal birds?

#

I'm still not getting them.

#

Oh I'm dumb.

#

Needed to adjust the bird start and end times.

#

Okay, yeah without the .hour works too!

#
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 241, in <module>
    generate_bird_offers(player_list[0], generate_bird_spawns(generate_offering_bird_spawn_locations(player_list[0], offering_bird_location_list), offering_bird_list))
  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 137, in generate_bird_offers
    offering = random.choices(population=[i for i in offerings_available], weights=[i.get_probability() for i in offerings_available], k=1)[0]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Shay\AppData\Local\Programs\Python\Python311\Lib\random.py", line 507, in choices
    total = cum_weights[-1] + 0.0   # convert to float
            ~~~~~~~~~~~^^^^
IndexError: list index out of range
#

Didn't we fix this one?

clear thorn
#

Did you change something for your population and not your weights

#

Remember any change to one has to be done to the other

regal adder
#

Yeah I remember that but I don't think so?

clear thorn
#

Where you just changed the hours back to time

#

I'm guessing the other one in that statement still needs done

regal adder
#

Nope. No mention of hours anywhere.

#

How can we print the population and weights to see what's going on?

#
def generate_bird_items(item_list, player_reputation):
    bird_items_offered_count = get_bird_offering_count(player_reputation)
    available_items = []
    item_selection_list = []
    for item in item_list:
        if item[2] <= player_reputation:
            available_items.append(item)
    for i in range(0, min(bird_items_offered_count,len(available_items))):
        item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
        item_selection_list.append(item_selection)
        available_items = [item for item in available_items if item[0] != item_selection]
    return item_selection_list
``` this is the old version if that helps at all.
clear thorn
#

Hm, yeah it's fine with that

#

Looked at it again and it says it's failing in generate_bird_offers()

regal adder
#

Yeah but I don't believe we modified the population or weights here did we?

clear thorn
#

I mean

#

I didn't XD

#

oh wait

#

Is the list empty?

#

That would throw an error

regal adder
#

?

#

Nope.

clear thorn
#

offering = random.choices(population=[i for i in offerings_available], weights=[i.get_probability() for i in offerings_available], k=1)[0]

If there are no items in offerings_available

regal adder
#

Wait.

#

It's only giving an error sometimes.

clear thorn
#

It's randomly picking birds

#

If it randomly picks birds not allowed in this time

#

No items

regal adder
#

I thought we made it so it could only pick birds allowed in this time?

#

I thought that's what this did. ```py
bird_spawn_list[i] = random.choices(population=[i for i in offering_bird_list if is_time_between(i.get_spawn_time_start(), i.get_spawn_time_end(),current_time)], weights=[i.get_probability() for i in offering_bird_list if is_time_between(i.get_spawn_time_start(), i.get_spawn_time_end(),current_time)], k=1)[0]

#

Isn't this saying that the random choices are limited by those that equate to true when their start and spawn times enter the is_time_between function?

clear thorn
#

Hm, yep, that is why that's there

#

But the list is empty

#

For one reason or another

regal adder
#

But only sometimes... ๐Ÿค”

clear thorn
#

Oh, mine works again

#

I'm currently in hour 21. You have no birds that spawn in hour 21

regal adder
#

Mine's this.

#Dynamically creates a list of all OfferingBird objects.
    offering_bird_data = [
        ("Courigeon", 80, datetime.time(4,0,0), datetime.time(22,0,0), ["Wellspring Village", "Location 2", "Location 3"]),
        ("Baublekaw", 80, datetime.time(4,0,0), datetime.time(22,0,0), ["Wellspring Village", "Location 2"]),
        ("Trinketalon", 80, datetime.time(4,0,0), datetime.time(22,0,0), ["Wellspring Village"]),
        ("Outflit", 80, datetime.time(20,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Hautehoot", 80, datetime.time(20,0,0), datetime.time(4,0,0), ["Wellspring Village"]),
        ("Vogueowl", 80, datetime.time(20,0,0), datetime.time(4,0,0), ["Wellspring Village"])]

#

So it should still be working 100% of the time.

#

Always something that will be spawning.

clear thorn
#

Ah, yep, yours covers it

#

Strange then

#

Gonna have to track back and log outputs to see where and why the list comes up empty

regal adder
#

On it!

#

And we're looking at offerings_available, correct?

#

Or are we 100% sure it's that the birds list is empty sometimes?

clear thorn
#

If this is still the error you're getting, yeah

  File "c:\Users\Shay\Documents\MyCode\MyPythonCode\NotPokemonBirdTrades.py", line 137, in generate_bird_offers
    offering = random.choices(population=[i for i in offerings_available], weights=[i.get_probability() for i in offerings_available], k=1)[0]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Shay\AppData\Local\Programs\Python\Python311\Lib\random.py", line 507, in choices
    total = cum_weights[-1] + 0.0   # convert to float

#

Right now the issue is with the list index out of range on offerings_available

#

To be certain, you could always run these just before that line:

print("Population",[i for i in offerings_available])
print("Weights",[i.get_probability() for i in offerings_available])
#

That would show you the exact lists that are being generated for random.choices

regal adder
#

Oh weird.

#
Population [<__main__.OfferingBirdItem object at 0x000001712D2B0510>, <__main__.OfferingBirdItem object at 0x000001712D2B0590>, <__main__.OfferingBirdItem object at 0x000001712D2B05D0>, <__main__.OfferingBirdItem object at 0x000001712D2B0610>, <__main__.OfferingBirdItem object at 0x000001712D2B0650>, <__main__.OfferingBirdItem object at 0x000001712D2B0550>]
Weights [40, 10, 85, 5, 5, 5]
Population [<__main__.OfferingBirdItem object at 0x000001712D2B0510>, <__main__.OfferingBirdItem object at 0x000001712D2B0590>, <__main__.OfferingBirdItem object at 0x000001712D2B0610>, <__main__.OfferingBirdItem object at 0x000001712D2B0650>, <__main__.OfferingBirdItem object at 0x000001712D2B0550>]
Weights [40, 10, 5, 5, 5]
Population [<__main__.OfferingBirdItem object at 0x000001712D2B0590>, <__main__.OfferingBirdItem object at 0x000001712D2B0610>, <__main__.OfferingBirdItem object at 0x000001712D2B0650>, <__main__.OfferingBirdItem object at 0x000001712D2B0550>]
Weights [10, 5, 5, 5]
Population [<__main__.OfferingBirdItem object at 0x000001712D2B0610>, <__main__.OfferingBirdItem object at 0x000001712D2B0650>, <__main__.OfferingBirdItem object at 0x000001712D2B0550>]
Weights [5, 5, 5]
Population [<__main__.OfferingBirdItem object at 0x000001712D2B0610>, <__main__.OfferingBirdItem object at 0x000001712D2B0650>]
Weights [5, 5]
clear thorn
#

hrm, what

#

That looks fine

regal adder
#
BIRD Hautehoot
Rare
BIRD OFFERING LIST [<__main__.OfferingBirdItem object at 0x000001F859160590>, <__main__.OfferingBirdItem object at 0x000001F8591605D0>, <__main__.OfferingBirdItem object at 0x000001F859160610>, <__main__.OfferingBirdItem object at 0x000001F859160650>, <__main__.OfferingBirdItem object at 0x000001F859160550>]
ALL OFFERINGS Wrist - Wraps - Bloodied
ALL OFFERINGS Running Shoes
ALL OFFERINGS Fingerless Gloves - Black
ALL OFFERINGS Fur-collared Jacket
ALL OFFERINGS Wellspring Village Pendant
OFFERINGS AVAILABLE [<__main__.OfferingBirdItem object at 0x000001F859160590>, <__main__.OfferingBirdItem object at 0x000001F8591605D0>, <__main__.OfferingBirdItem object at 0x000001F859160610>, <__main__.OfferingBirdItem object at 0x000001F859160650>, <__main__.OfferingBirdItem object at 0x000001F859160550>]
Population [<__main__.OfferingBirdItem object at 0x000001F859160590>, <__main__.OfferingBirdItem object at 0x000001F8591605D0>, <__main__.OfferingBirdItem object at 0x000001F859160610>, <__main__.OfferingBirdItem object at 0x000001F859160650>, <__main__.OfferingBirdItem object at 0x000001F859160550>]
Weights [10, 85, 5, 5, 5]
Population []
Weights []
#

This one was the last before it errored.

clear thorn
#

Ope, that one's not

#

So yeah, something is making that list empty

#

offerings_available

regal adder
#

It just instantly drops everything.

clear thorn
#

What's your full function?

#

I'm not getting this error lol

regal adder
#
def generate_bird_offers(player_name, bird_spawn_list):
    offerings_available = []
    offerings_displayed = []
    for bird in bird_spawn_list:
        if bird:
            print(f'BIRD {bird.get_offering_bird_name()}')
            if bird.get_offering_bird_name() in ["Courigeon"]:
                player_reputation = player_name.get_bird_reputation_common()
                print("Common")
            if bird.get_offering_bird_name() in ["Baublekaw", "Trinketalon"]:
                player_reputation = player_name.get_bird_reputation_uncommon()
                print("Uncommon")
            if bird.get_offering_bird_name() in ["Outflit", "Hautehoot", "Vogueowl"]:
                player_reputation = player_name.get_bird_reputation_rare()
                print("Rare")
            bird_offering_count = get_bird_offering_count(player_reputation)
            print(f'BIRD OFFERING LIST {bird.get_offering_list()}')
            for offering in bird.get_offering_list():
                print(f'ALL OFFERINGS {offering.get_item_name()}')
                if offering.get_reputation_requirement() <= player_reputation:
                    offerings_available.append(offering)
            print(f'OFFERINGS AVAILABLE {offerings_available}')
            for i in range(0, min(len(bird.get_offering_list()), bird_offering_count)):
                print("Population",[i for i in offerings_available])
                print("Weights",[i.get_probability() for i in offerings_available])
                offering = random.choices(population=[i for i in offerings_available], weights=[i.get_probability() for i in offerings_available], k=1)[0]
                offerings_displayed.append(offering)
                offerings_available = [offering for offering in offerings_available if offering not in offerings_displayed]
                print(f'AVAILABLE {offerings_available} DISPLAYED {offerings_displayed}')
#

Did I miss a change?

clear thorn
#

Hm, I don't have the [0] at the end of random.choices()

#

And I dunno if that's right or not lol

regal adder
#

You said to add it back earlier I believe.

#

Oh I remember.

#

Without it, it was duplicating the list or something.

clear thorn
#

oof, I am not sure

#

It's happening because offerings_available winds up empty

regal adder
#

Me neither. I don't see any patterns to what's happening before those are empty.

clear thorn
#

Just not sure why, it's gotta be a bug in the deduplication logic

regal adder
#

Well the old one looked like this and it worked.

def generate_bird_items(item_list, player_reputation):
    bird_items_offered_count = get_bird_offering_count(player_reputation)
    available_items = []
    item_selection_list = []
    for item in item_list:
        if item[2] <= player_reputation:
            available_items.append(item)
    for i in range(0, min(bird_items_offered_count,len(available_items))):
        item_selection = random.choices(population=[i[0] for i in available_items], weights=[i[1] for i in available_items], k=1)[0]
        item_selection_list.append(item_selection)
        available_items = [item for item in available_items if item[0] != item_selection]
    return item_selection_list
#

Maybe I didn't change something over properly?

clear thorn
#

I have no idea

#
            for i in range(0, min(len(bird.get_offering_list()), bird_offering_count)):
                if len(offerings_available) == 0:
                    break
#

This fixed it though lol

#

That's the best I've got for the moment

regal adder
#

I mean, I don't know if that's a fix. ๐Ÿ˜„

#

Because that list should never be empty.

#

Might be the best for today though.

clear thorn
#

We call that a "band aid" XD

regal adder
#

For today at least. I'm going to watch some YouTube and get some sleep. Thanks for all of your help. You've been fantastic!

clear thorn
#

Have a good one!

regal adder
#

You as well!

grizzled glacierBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.