Ok, heading towards the edge of my knowledge here. What do I change so that item.getCount( KoLConstants.inventory ) doesn't return 1 for both Staff of Ed's, despite only name and not ItemId matching. I guess it's something to do with how matching works for a List<AdventureResult>, and I have to change the matching to be name + itemId rather than just name, but I don't even know where this is set.
That uses list.indexOf to find the AdventureResult in the list. That seems to be specified to use the "equals" method on the objects in the list.
Look at AdventureResult.equals:
Code:
return ( !ar.isItem() || this.itemId == ar.itemId ) &&
this.name.equalsIgnoreCase( ar.name );
It looks like that does look at itemIds for objects and otherwise does a case insensitive comparison on the name.
Perhaps the implementation actually uses compareTo for some reason?
Look at AdventureResult.compareTo.
- If "priority" is different - ITEM vs. EFFECT, for example - the difference in priority determines the comparison.
- Else, the objects are the same type, and the "name" is examined. If they are equal, the items are deemed to be equal.
- Else, the names are different, and effects are sorted based on duration and everything else is sorted based on name difference.
I find it suspicious that equals() and compareTo() for adventure results don't agree on what to look for; if a.equals( b ), as implemented, that does NOT mean that a.compareTo( b ) == 0. That can't be right.
Why are these focusing on names? The "name" is the only thing that all AdventureResult objects have, and the assumption was that the namespace for each type of object did not allow duplicates. That is no longer the case. In fact, it was already broken for effects - there are 6 different effects that KoL calls "A Little Bit Evil" - but we had a kludge in place for those to give them different names.
Now we have both objects and effects which can have identical names and different "id"s. Interestingly enough, every AdventureResult object has the following fields:
Code:
protected String name;
protected int priority;
private int count;
private int itemId;
and the "itemId" field really is stored only for items. Compare to ASH's "Value" object:
Code:
public Type type;
public long contentLong = 0;
public String contentString = null;
public Object content = null;
where every object has both a string (the "name") and a "long" (the "id") and may have a pointer to an arbitrary data structure.
I would instinctively have believed that all fields in a datatype would have to be equal for them to be considered equal, but it seems this is not the case.
True. And I think that compareTo and equals not agreeing is a Bad Thing.
You can imagine this throws quite a problem into the mix!
I suggest the following:
- AdventureResult has "name" and "id"
- Everything has a "name" and "id" defaults to 0. For items and effects, "id" is set to the specific itemId or effectId.
- AdventureResult.equals requires that priority, id, and name all match - and I see no reason to have the name match be "ignoreCase".
- AdventureResult.compareTo returns 0 (equals) iff AdventureResult.equals would return true:
-- If priorities are not equal, return priority comparison
-- If (priorities are equal and) names are not equal, return name comparison - and I think ignoreCase is fine, here, if the names are not equal, since that will make them sort the same as now.
-- If (priorities and names are equal) and ids are not equal, return id comparison
-- Otherwise, they are equal.