Heeft een speler niet genoeg cash meer om de huur te betalen, dan moet de speler huizen of straten verkopen of hypotheken opnemen op straten.
In deze aflevering bouwen we een flow waarin spelers hun cash balance kunnen aanvullen door:
- een hypotheek op te nemen op straten zonder huizen
- straten zonder huizen te verkopen aan de bank
- huizen terug te verkopen aan de bank
Voor de straten zonder huizen halen we eerste de Assets op die de speler in bezit heeft.

Omdat een hypotheek opnemen of de straat terug verkopen aan de bank alleen kan wanneer er geen huizen op staan, filteren we deze verzameling op het aantal huizen.

Number of Buildings is een nieuw formuleveld op het Asset object dat het aantal huizen dat erop gebouwd is als een getal weergeeft. Bij een hotel is de waarde 5. Het aantal huizen als een getal in plaats van tekst hebben, is voor flows als deze een stuk handiger, omdat we werken met optellen en aftrekken bij aankoop of verkoop van huizen. Achteraf gezien hadden we dit beter direct zo kunnen ontwerpen in plaats van een picklist te maken voor de gebouwen op de straat.
Omdat we de speler in één scherm de opties voor hypotheek opnemen, straten verkopen én huizen verkopen willen aanbieden, zetten we hier ook de flow ALF – Count Player’s Houses and Hotels als subflow in, die we de vorige aflevering gemaakt hebben.

De Building Transactions die als output uit deze flow komen, kunnen ook steden bevatten waar de speler wel alle straten heeft, maar waar geen huizen staan. Omdat we hier alleen maar huizen willen verkopen, kunnen we Building Transactions zonder huizen wegfilteren.

In de flow zullen we op meerdere momenten moeten checken of er wel huizen en/of straten zijn om te verkopen.
Daarvoor tellen we het aantal records in de gefilterde Assets en Building Transactions verzamelingen.

Deze twee getallen gebruiken we meteen om te checken of we de speler wel het scherm moeten tonen waarin je huizen en straten kunnen verkopen. Als ze geen huizen en straten bezitten, is dat immers niet nodig.

Heeft de speler geen bezittingen meer, dan leidt het N pad rechtstreeks naar het eindscherm van de flow.
Daarin krijgt de speler ofwel te zien dat de Cash Balance weer positief is geworden door de verkoop van straten en huizen, ofwel dat ze failliet zijn. Dit eindscherm wordt ook gebruikt wanneer de speler uiteindelijk door verkoop wel weer een positieve Cach Balance heeft bereikt.

Heeft de speler wel bezittingen om te verkopen, dan komt de speler bij het scherm uit waar ze kunnen invoeren wat ze willen verkopen of waar ze een hypotheek op willen opnemen.

De sectie Sell or mortgage streets is alleen zichtbaar wanneer de speler Assets (straten) zonder huizen heeft. Hetzelfde geldt voor de Repeater die daaronder staat.
De teksten en keuzemogelijkheden in elk repeater element zijn ook weer voorwaardelijk zichtbaar. Als er al een hypotheek rust op de Asset is kwestie, kan de speler de Asset alleen nog verkopen en wel voor de helft van de waarde.
Rust er nog geen hypotheek op de Asset, dan heeft de speler ook de mogelijkheid om een hypotheek op te nemen. Dan krijgt de speler de helft van de waarde van de Asset van de bank.
Daaronder zal de speler voor elke stad waar huizen staan de optie krijgen om maximaal dat aantal huizen te verkopen dat er in die stad gebouwd is.

Hiervoor bepalen we de maximale waarde voor de slider met het aantal gebouwde huizen van de stad, net zoals bij de flow waarin de speler huizen kan kopen.

Nadat in dit scherm de keuzes van de speler zijn opgehaald, kunnen de verkopen verwerkt worden. Eerst verwerken we de hypotheken en verkopen van straten.

Omdat bij verkopen aan de bank het eigendom aan de bank moet worden overgedragen, moeten we eerst de bank van de juiste Game ophalen.

Vervolgens evalueren we elke Asset in een loop over de Repeater elementen.
In het Repeater element zelf, is door de gebruiker de keuze gemaakt om ofwel een hypotheek te nemen op de Asset, of deze te verkopen aan de bank, of er niets mee te doen.

Het Repeater element bevat maar zeer beperkte gegevens van de Asset. Het Record Id en alle gegevens die zichtbaar zijn voor de gebruiker in het Repeater element. Dus om verdere gegevens van de Asset erbij te halen en de Asset te kunnen bijwerken, moeten we gaan filteren in de oorspronkelijke collectie van Assets zonder gebouwen. We filteren dan op Id is gelijk aan de Id van het Repeater element.
Over deze gefilterde collectie van 1 Asset voeren we ook een loop uit. Binnen deze binnenste loop hebben we toegang tot gegevens uit de buitenste loop, dus wat de gebruiker in de Repeater heeft ingevuld en die van de binnenste loop, dus de Asset.

Verkopen aan de bank
Wanneer de Asset verkocht wordt aan de bank, moeten we de volgende updates maken:
- De Cash Balance van de speler wordt verhoogd met de waarde van de Asset
- De Bank wordt eigenaar van de Asset
- Als er een hypotheek op de Asset rust, wordt die opgeheven

Let op: als er een hypotheek op de Asset rust wanneer de speler deze aan de bank verkoopt, krijgt de speler maar de helft van de waarde van de Asset. Dit regelen we met de formule AssetSalesPrice.

De bijgewerkte Asset gaat in een update collectie, zodat we de daadwerkelijke update in de database na het afronden van alles loops in één bewerking kunnen doen.
Hypotheek opnemen
Als de speler de Asset niet verkoopt aan de bank, maar er een hypotheek op neemt, behoudt de speler de Asset wel, maar krijgt de speler maar de helft van de waarde van de Asset in Cash in handen.
Bij een Asset van € 20.000,- krijgt de speler € 10.000,- cash en mag er geen huur meer gevraagd worden als andere spelers op de straat komen.

Ook hier voegen we de bijgewerkte Asset toe aan de updateAssets collectie.

Na het afsluiten van zowel de binnenste loop over de Asset(s) en de buitenste loop over de Repeater elementen, checken we of er Assets verkocht of op hypotheek gezet moeten worden. Zo ja, dan updaten we de records in de updateAssets collectie en de inputPlayer record in de database.

Hierna regelen we de eventueel te verkopen huizen.
Huizen verkopen aan de bank
Eerst checken we of de speler wel Assets met huizen erop had. Zo niet, dan hoeven we het ook niet per stad (Asset Group) te bekijken. Daarvoor is dit eerste Decision element.

Wil de speler inderdaad huizen verkopen, dan halen we met een filter element en een loop over de gefilterde uitkomst daarvan de eigenlijke Building Transaction erbij.


Als uit deze Decision blijkt dat de speler inderdaad Assets met huizen heeft, dan is de Repeater om huizen te kunnen verkopen dus zichtbaar geweest op het scherm en kan de speler huizen willen verkopen. Daarom beginnen we dan met de loop over de elementen van deze Repeater.

Dan kunnen we binnen deze loop per Asset Group bekijken of de speler in die stad huizen wil verkopen aan de bank.

Het principe werkt hetzelfde als bij de nested loops die we eerder hebben gezien:
- In het filter element matchen we de juiste Building Transaction op basis van het Id van het Repeater element
- In principe komt hier één match uit, maar het blijft een collectie, dus daarom hebben we een loop nodig.
- In de binnenste loop hebben we dus de informatie van de hele building transaction record en wat er in de Repeater is ingevuld.
Een building transaction werkt zowel voor koop als verkoop, dus het aantal te kopen moet negatief zijn. Daarom wijzen we eerst 0 aan de transaction quantity toe en dan trekken we het aantal uit de slider ervan af.
Op dezelfde manier trekken we het aantal te verkopen huizen dat de gebruiker in de slider heeft aangegeven af van het aantal gebouwen dat er al staat in die stad.

Ook wijzen we het te verdienen bedrag van de transactie toe. Daar is de onderstaande formule voor. Als je huizen terug verkoopt aan de bank, krijg je daar de helft voor van wat je ervoor betaald hebt. Dus het te ontvangen bedrag is berekend als het aantal te verkopen huizen maal de helft van de normale koopprijs van huizen.

Om updates in de database buiten de loops te kunnen doen, voegen we de building transaction die we hebben bijgewerkt weer toe aan een collectie.

Vervolgens checken we weer met een Decision element of er records in de updateBuildingTransactions collectie zitten. Zo ja, dan updaten we ze in de database.
Hierna gebruiken we een subflow om de uitwerking van de building Transaction te verwerken in de Assets en Asset Groups.
Nadat dit afgehandeld is, kunnen we de Building Transactions zelf weer verwijderen.

Het afhandelen van Building Transactions in de subflow
De input variabelen die we aan deze flow meegeven zijn, de inputPlayer en een collectie aan Building Transactions. Aan het begin halen we alle Assets van deze speler op.

Nu gebruiken we deze subflow alleen bij het verkopen, maar deze kunnen we ook inzetten in het proces voor het aankopen van huizen. Dezelfde logica kan dan uit de hoofdflow voor dat proces weg.
Door op zichzelf staande subprocessen te herkennen, kun je modulair bouwen. Je kunt voor elk deelproces een eigen flow bouwen en die als subflow gebruiken in verschillende processen waar deze stap bij nodig is. Hierdoor hoef je de logica maar op één plaats te onderhouden in plaats van binnen meerdere flows die dezelfde stappen bevatten.
De tweede stap in deze flow is een loop over alle Building Transactions. Daarbinnen filteren we uit alle Assets van de speler alleen de Assets binnen de Asset Group waar de huidige Building Transaction over gaat.

Stel dat je in een stad met 3 straten 10 huizen over hebt na de verkoop, dan weet je al dat er bij elke straat sowieso drue huizen moeten staan en bij één ervan ook een vierde huis. We willen natuurlijk niet 3 of 4 keer over elke straat moeten loopen, dus gebruiken we een formule om eerst deze grootste gemene deler (hier 3 dus) al te bepalen.
De formule voor het aantal huizen dat in elk geval in elke straat moet staan, is deze:

Als we de getallen van het bovengenoemde voorbeeld hier invullen, werkt de formule als volgt:
10 / 3 = 3,333, maar dat ronden we af naam beneden, dus is de uitkomst 3.
Met behulp van deze formule kunnen we aan elke straat in de stad al de eerste drie huizen toewijzen, maar we hebben de ‘rest’ ook nog nodig om te verdelen. Daar gebruiken we de formule hieronder voor. Die werkt met de aantallen uit het voorbeeld als volgt: 10 – ( 3 * 3 ) = 1.

Wat we hiermee doen is het volgende:
- De uitkomst van deze ‘rest’ formule wijzen we toe aan een getal variabele

- Elk van de Assets komt één keer langs in de loop
- Aan elke Asset worden sowieso 3 huizen toegewezen

- Zolang het ‘rest’ aantal hoger dan 0 is nog één extra


- Van dit rest aantal wordt dus ook in elke loop iteratie weer één afgetrokken omdat dit huis dan aan een straat is toegekend. In dit voorbeeld wijzen we aan de eerste straat 4 huizen toe en trekken we dan 1 af van het ‘rest’ getal.
- Bij de tweede en derde straat is dat restgetal dus niet meer groter dan 0 en daarom krijgen deze straten geen vierde huis.
- De buildingsEquallyDividedText formule die hier aan het
Buildingsveld wordt toegewezen, is een voortvloeisel uit het besluit helemaal aan het begin van de serie om daar een picklist veld met een waarde in tekst van te maken. Pas later hebben we hetNumber of Buildingsveld toegevoegd, maar er was al de nodige functionaliteit afhankelijk van hetBuildingsPicklist veld. - En uiteraard voegen we binnen de Assets loop steeds elke Asset toe aan een collectie waarmee we uiteindelijk na het sluiten van de loops alle Assets in één keer bijwerken.
Na het beëindigen van de Assets loop, zitten we wel nog binnen de loop over de Building Transactions. Het bijwerken van de Cash Balance van de speler doen we per Building Transaction en dus na het sluiten van de Asset loop, maar nog wel binnen de Building Transactions loop.


Na het verlaten van ook de buitenste loop, voeren we de updates uit op de Assets, om de nieuwe aantallen huizen daarin op te slaan in de database en de speler om hun Cash Balance bij te werken.
Omdat we deze flow nooit zullen activeren als er geen huizen te kopen of verkopen zijn, kunnen we hier de ‘null checks’ achterwege laten. In de dagelijkse praktijk is het altijd een goed idee om deze wel te gebruiken.

Null checks in het kort
De roze elementen in flows, kunnen tot vastlopen leiden als er iets niet in orde is met de data, zoals:
- Er wordt een variabele in een Get element als filter gebruikt die geen (juiste) waarde heeft
- De flow probeert een update uit te voeren op een record collection variabele waar geen enkele record in zit.
- En dit geldt hetzelfde bij aanmaken en verwijderen van records
Door vooraf te checken of die variabelen niet leeg zijn, kun je zorgen dat de database interactie niet geprobeerd wordt als je door je check van tevoren al weet dat die niet kan slagen.
Terug naar de screenflow
Bovenstaande stuk om de transacties te verweken, zit in een subflow. Voor we de subflow in doken, liet ik al zien dat we de Building Transactions nadat ze door de subflow verwerkt zijn ook weer verwijderen.
Hier heb ik vanaf het delete element een Fault Path toegevoegd. Zo’n Delete zou ook tot een foutmelding kunnen leiden als er een opdracht in gegeven wordt om records te verwijderen en een of meerdere daarvan al verwijderd zijn. Mocht zoiets gebeuren door een andere flow of door een beheerder die enthousiast data aan het opruimen is, dan willen we hoe dan ook voorkomen dat flow hier vastloopt. Het Fault Path leidt net als de gewone connector naar de volgende Assignment, waarin we de Building Transactions record collection variabele leeg maken voor het geval de speler de flow nog een keer moet doorlopen.


Waarom zou de speler de flow nog een keer moeten doorlopen?
Terwijl de speler in het scherm aangeeft welke straten ze willen verkopen, waar ze een hypotheek op willen nemen en hoeveel huizen ze willen verkopen, kunnen we niet meteen via een screen actions de opbrengst berekenen en kunnen er dus ook niet op valideren of de speler daardoor wel uit de orde cijfers komt. Dit heeft onder andere te maken met dat je geen screen actions kunt voeden met data uit een Repeater.
Het kan dus voorkomen dat de speler wat straten en huizen verkoopt, maar met de opbrengst daarvan nog niet voldoende geld heeft om een positieve Cash Balance te bereiken. In dat geval, zal de speler opnieuw naar het invoerscherm moeten worden geleid en uit de resterende straten en huizen moeten kiezen wat nu te verkopen.
De speler mag het einde van deze flow niet bereiken voor hun Cash Balance weer positief is. Hiervoor zorgen we met een Decision element. Alleen wanneer de Cash Balance van de speler groter dan 0 is, mag de speler verder naar het Final Screen. Zo niet, dan wordt de speler terug geleid naar het begin van de flow. In deze nieuwe ronde wordt gekeken naar de actuele bezittingen en Cash Balance, dus twee keer hetzelfde verkopen, zal niet gebeuren.


Het Eindscherm
Uiteindelijk bereikt de speler altijd het eindscherm, ofwel omdat de speler weer geld heeft, ofwel omdat de speler nog steeds schulden heeft na verkoop van alle bezittingen. Dat eindscherm en de route erheen bij faillissement hebben we ook al gemaakt.
Waar past deze flow in het totaalplaatje?
Deze flow moet direct wanneer de speler een negatieve Cash Balance heeft gestart worden. Omdat de speler de hele beurt uitvoert binnen de SCR – Roll and Move flow, zullen we deze flow daar ergens moeten invoegen.
Daarnaast moeten we een manier hebben om de flow op te starten als de speler in het rood zou komen buiten de eigen beurt, bijvoorbeeld doordat er vanwege een kans kaart geld aan een andere speler betaald met worden.
Tot slot moeten we regelen dat een speler die failliet is niet meer aan de beurt komt.
De eerste plek waar se speler mogelijk in het rood kan komen, is bij het verlaten van de gevangenis tegen betaling van € 5.000,-.

Verder na deze beide al aanwezige Decisions waarin gecheckt wordt of de Cash Balance van de speler nog positief is.

Om te voorkomen dat een failliete speler nog aan de beurt komt, gaan we het volgende doen:
- Op het Player Object voegen we een nieuw Checkbox veld genaamd
Bankrupttoe - In de SCR – Sell Buildings or Assets flow voegen we een update toe om dit vinkje aan te zetten wanneer de speler failliet is.
- In de ALF – Start next Player’s Turn flow voegen we een conditie aan de Get elementen waarmee we de volgende speler opzoeken




Volgende keer
Naast bezittingen terugverkopen aan de bank, kun je natuurlijk ook bezittingen verkopen aan andere spelers. Daar gaan we in de volgende aflevering mee aan de slag.