Witcher.aia (257.4 KB)
In the 'Battle' screen, when it is the player's turn, no matter the action picked, there is a runtime error concerning either list item selection or replacement. I just started using app inventor so this is my first big project, and so it has a lot of spaghetti code so I can easilly understand everything. I don't know where to start looking for the problem. (also plkease excuse my english, it isn't my first language)
I love the Witcher franchise.
RPG s are heavily table based, where the monsters and their attributes are kept in lookup tables with their strengths and weaknesses, and you only need to code the battle logic once.
New monsters and weapons are just extra rows in those tables.
Likewise for weapons, potions, and battle choices.
So here's you reading list for the day:
-
The Do It facility from FAQ Section: Debugging
-
Lookup tables, both lists and dictionaries, from FAQ Section: Lists
and
FAQ Section: JSON and Dictionaries
My downloaded blocks image of your blocks is failing upload to this board.
Looking at your blocks, I see some text blocks that might be intended to have trailing blanks in them when building up a text JOIN of them for a TinyDB tag. Beware, AI2 trims training blanks from text blocks. You have to go back and edit them in again.
Further comment requires a screen shot of the exact error message and Do It values of all the participating values.
I got some time to run your code and appply Do Its.
I'm in Screen1, where you distribute attribute points for character creation.
Here's where you do that:
You fail to check if the Selection Index is in range 1..length of list(stat_list) before trying to increment that index in the stat_list list.
Add an extra if/then test to guard that code, and check to see if you need an extra Notifier component for different confirmation dialogs.
Word of caution:
Resetting the Elements of a ListView probably resets its SelectionIndex to 0.
So grab it and save it somewhere as soon as possible.
I came across the battle rules for your app in the Designer attributes in the info screen.
For convenience, I'm copying them here to make it easier to read and compare to your code.
Info
Info
This is a mobile game made in app inventor in about a week. It was made with homemade rpgs like DnD in mind and to pass the time with small and quick battles. Thank you for downloading and playing!
Stats
Stats
The played character has a list of these 9 tracked statistics:
- Level,
- Vitality,
- Attribute points,
- Armour,
- Strength,
- Speed,
- Combat,
- Magic and
- Charisma.
The last six are on a point scale of 1-100 and they are used in combat (except Charisma) to calculate each interaction.
Level is calculated using the sum of the character points divided by 20 and it generally only serves as an indicator of your strength compared to monsters.
Vitality always begins at 100 points and when depleted you lose the battle.
Attribute points are won through battle and can be used to upgrade your stats.
To disable the 100 point cap on stats look for the relevant option in the settings
Enemies
Enemies
There are currently 10 different types of enemies in the game, with each of them having some special characteristics.
For the first five types of enemies, swarm battles are unlocked after defeating them for the first time, which allows you to battle multiple of them in each battle.
Each enemy has a relative danger level that determines it's stats.
Every enemy is randomly generated to have 15 points distributed per level among their three tracked statistics:
- Armour,
- Strength and
- Speed,
which are used in combat calculations.
For an increased challenge you can make enemies have the same level as you do. Look for enemy upscaling in the settings.
Battle
Battle
After initiating a battle, the character will be be put up against the enemies he has selected (or the default option of one ghoul).
Depending on each character's speed, the turn order will be calculated. Every character can do an action and then attack on their turn.
The played character and each monster type have a unique set of actions that apply effects.
Your available actions are:
- Attacking stance, which slightly increases your attack power,
- Defensive stance, which slightly increases your defensive ability,
- Healing Potion, which passivly restores health,
- Fire spell, which applies a burn to the chosen enemy,
- Shield spell, which reduces or blocks enemy damage and
- Confuse spell, which slows or stuns enemies.
Those factors and the stats of the attacker and the defender will be used in calculations to deal damage on the defender's Vitality.
When a monster's Vitality reaches zero it dies and if there are no monsters left, the battle ends in a victory and the character is rewarded with Attribute Points.
If the character's Vitality reaches zero, you have lost the battle but you will not be punished in any way.
You can see more information about the calculations below.
You can visit the Bestiary and refresh your memory or learn more information and tactics for each enemy type. If you want an easier or maybe a tougher time you can change the difficulty in the settings.
Calculations
Calculations
When first entering a battle the turn order is established by comparing the speed stats.
Starting with the order of most to least speed, each character gets 2 turns for every 20 more speed compared to the slowest enemy that they have(i.e. a battle with three characters 1, 2 and 3 of speed 25, 20 and 5 accordingly, would have a turn order of 1, 1, 2, 3).
During their turn, the character chooses an action that will have an immediate or a passive effect over the next or next few turns.
The played character's actions are:
- restore 2 Vitality for the next two turns,
- deal 2 damage to the chosen enemy for the next two turns (only one enemy at a time),
- block an attack if calculated damage is equal or less of 5, and lastly,
- decrease targeted enemy Speed by 0.1* Magic for the next turn and have a Magic * 0.8 * 100% chance to disallow their next attack.
Then (unless forbidden by an action) the character will attack, with the base calculation being: round(0.2* Strength - 0.15* Enemy Armour).
The played actions can change these calculations, for example the played character's actions can add +0.15Combat or +0.1 Magic damage to enemies or -0.1Combat or -0.05 Magic damage for the next enemy attack.
If the damage calculated is less than five, then the damage dealt will be five (excluding flat damage dealt).
If a battle is won, the player gains round(0.5* Suggested Level) amount of Attribute points.
Your screen loading needs work, to avoid eventually filling memory.
Screens should be closed as often as they are opened.
I'm still trying to figure out what's in your global variables.
However, I see spots in your code that fail dimensional analysis:
Here you are looking to select item 2 of a value that might come back as a non-list from TinyDB.
That's begging for an untraceable error if it happens.
Yeah the reason I put the load screen was beacuse I wanted to deal with that problem. I think I read somewhere that app inventor has 2 screens loaded at a time (the one you are using and the previous one that becomes backpressed), but I don't exactly know how that system works. Should I just put a block in every screen, so that it closes if the screen is backpressed?
This probably helps most of the time but I think I shouldn't do it this time to avoid adding more variables and tinydb tags. Every case where the list view is reset is either screen initializing or after already having picked what the player wants and the relative actions have been done, so I dont think the selection index being reset causes any problem.
Thanks for the addition. I just implemented it and now I am gonna check if the battle screen still works, and if it doesn't I'm gonna at least try and figure out what the problem is. Thank you for all your help thus far and I will be grateful for any further help if needed!
I just tested the battle screen and the problem persists. An example of what my problem is: ' The operation select list item cannot accept the arguments: , [0], [2]
Note: You will not see another error reported for 5 seconds.' is the runtime error I am shown when trying to attack while using the shield action, as seen in the screenshot from the companion (but the same or similar messages are shown with any action selected). I also had seen a tipwhere you could more easilly detect where the error occured by using the bellow blocks, but the label doesn't change when an error happens.
That depends on the screen transition graph.
The screen switching section of the FAQ Screens has sample code for that.
Have you tried single stepping the blocks using the Do It debugging facility?
Also, I noticed that you have not used
- Value procedures
- Procedure parameters
Those could shrink the code for increased clarity.
I found myself lost in your data forest.
To guard against this type of error, extra checks are needed in the code, for
- is the list really a list (is a list block)
- is the list long enough (length of list >= 2)
That extra error checking wrapper is a good place to add Notifiers announcing what assumptions proved wrong in the code.
I did some single stepping with Do It and searching with Ctrl-F in the Blocks Editor.
Battling a ghoul, after confirming a stance:
The error happens when fire effects are calculated.
The fire global is supposed to be a list with at least two items.
Your Battle.Initialize:
You make the same mistake with the confuse global variable.
Consider adding a comment bubble to the Battle.Initialize even documenting your global variables?
Getting past the wrongly initialize fire and confusion lists, your next error is
It would help knowing how you handle the turn-related lists.
All the turn related lists are reset upon initializing the screen and then they are changed whenever the calculate order procedure is called. Firstly I create the speed_list by adding the speeds of the player and all the enemies.then I make a new list called speed order from sorting that list in order from fastest to slowest (I do this so later when showing the turn order it can recall which speed belongs to which character). Later I create the turns_list. Through some maths it basically makes a list where if a character is n*20 faster than the slowest character then he gets 2^n turns (i.e. if there are 3 characters with speeds 45, 25 and 5,they get 4, 2 and 1 turns respectively) Finally the turn list is created by repeating an algorithm where if a character has more than 1 turn a variable 'next' is calculated by dividing their turn number by that of the next character. If next is other than one, it adds the character index to the turn list 'next' number of times and the next character's index one time before deducting those turns from the turn list and going back and checking again for that charcter if next is other than one. If at any time it isn't then it just adds one turn to the turn order and deducts one from the turns_list. The same happens when it reaches the last character. Then, just for better visuals, I deduct the indices on the turn list by one (so that in the list, for example, 1 represents enemy one) and then convert the 0 to 'Player'. Whenever I tested for the turn order it didn't show any broplems so I don't know what I did in the battle phase so it becomes problematic.
I also forgot to say that I also have a 'turn' list, which I use to see if it's the player's turn and to know which enemy's stats to calculate for their attack. The second index says in which turn we are and goes back to 1 when the turn order is exhausted. The first index is the number/name from the turn_list. I now suspect that the problem is caused by the blocks below, which I use to go to the next turn.