DDM Bouwvakkers handleiding


deel 3


Geschreven door: Timo Krul (mrfan@dds.nl).
Laatste wijzigingen: Mei'95.


Inhoud



Deze handleiding bevat de volgende hoofdstukken:


Eindelijk...



Hier is dan eindelijk deel 3 van de handleiding. Het heeft een beetje lang geduurd, maar het resultaat is er ook naar. (Hmm.. hoe weet ik dat nou?, ik heb nog maar 2 regels getikt...). Nouja, laten we maar weer eens wat met verbs gaan doen. Handig om te weten zijn de commando's:

/e object:verb om een verb te editten.
/re om weer terug te komen in de editor na een foutmelding.

Als je iets wilt testen van de dingen die uitgelegd worden, dan kan je een eigen test verb maken:
@verb me:test

Met /e me:test kan je hier naar hartelust in gaan programmeren. En als je test intikt, wordt de verb dus uitgevoerd.


Constructies



In het vorige deel stond de if-constructie uitgelegd. Hier nog even een volledigere beschrijving. Alles zal ik uitleggen met behulp van een voorbeeld.
Allereerst het simpelste geval:
if (player.name == "Harry") 
  player:tell("Wat een mooie naam.");
endif
In plaats van is gelijk wil je misschien wel testen op is ongelijk dat doe je met != dus:
if (player.name != "Harry")
  player:tell("Jij heet dus geen Harry."); 
endif
Let op: Vergeet nooit endif!

Er is ook een mogelijkheid om, zoals we al gezien hadden, een else te gebruiken:

if (player.name == "Harry")
  player:tell("Wat een mooie naam.");
else
  player:tell("Jij heet dus geen Harry.");
endif
Maar misschien wil je wel op meer namen testen, dan kan je elseif gebruiken:
if (player.name == "Harry")
  player:tell("Wat een mooie naam.");
elseif (player.name == "Frank")
  player:tell("Heb jij effe pech met zo'n naam.");
else 
  player:tell("Je heet geen Harry of Frank.");
endif

Vraagteekuntjuh



Je zult vast wel een keer in de situatie komen dat je effe iets snel wilt oplossen zonder helemaal een if te gebruiken. In dat geval kan je vaak het ?-teken gebruiken. Als je slim bent kan je hier heel veel situaties heel effectief mee oplossen. Aan de linker kant van het vraagteken zet je de expressie en aan de rechterkant wat de uitkomst moet zijn wanneer deze expressie waar is, respectievelijk onwaar is, gescheiden door een |.

Lekkere duidelijke uitleg he? Nee zeker... nou bekijk dit eens:

manofvrouw = player.gender == "mannelijk" ? "man" | "vrouw";
player:tell("Je bent een ", manofvrouw, ".");
Aan de linkerkant van het vraagteken staat de vergelijking of de speler mannelijk is. Als dat zo is, dan levert dit het woord man op en anders het woord vrouw.
Dit kan trouwens zelfs in 1 regel opgelost worden met:
player:tell("Je bent een ", player.gender == "mannelijk" ? "man." | "vrouw.");
Hint: over het algemeen is het handiger op naar de voornaamwoorden te kijken wanneer je op geslacht wilt controleren. Je weet wel, die properties als .pp, .ps, ppc, enzovoorts. Als .pp gelijk is aan "hij", dan kan je d'r vanuit gaan dat je met een mannelijke speler te maken hebt.

Bekijk nu de volgende regels eens:

ad = length(player.contents);
if (ad > 1)
  player:tell("Je hebt ", ad, " dingen."); 
elseif (ad)
  player:tell("Je hebt 1 ding.");
else 
  player:tell("Je hebt geen dingen.");
endif
Dit kan veel korter met:
ad = length(player.contents);
player:tell("Je hebt ", ad ? ad | "geen", " ", ad == 1 ? "ding" | "dingen.");

While



Met while kan je ook leuke dingen doen. Wist je trouwens al dat je zomaar variabelen uit de lucht kan plukken? Net als hierboven manofvrouw en ad kan je eigenlijk alles wel gebruiken wat in je opkomt (behalve namen die gereserveerd zijn voor andere dingen, maar je merkt het gauw genoeg als het fout gaat...).

Zo kan je bijvoorbeeld een tellertje in een while-lus gebruiken:

player:tell("De tafel van 7:");
tellertje = 1;
while (tellertje < 11)
  player:tell(tellertje, " keer 7 is ", tellertje * 7);
  tellertje=tellertje + 1;
endwhile
Vergeet endwhile niet!

Als je tellertje tot 10000 laat lopen zou je heel veel power van de computer gebruiken. Om het eerlijk te houden, krijgt iedere verb maar een bepaald aantal ticks. Op een gegeven moment zal de verb er dus dus mee ophouden met een foutmelding dat de ticks op zijn. Je kunt dit verhelpen door steeds even te wachten voordat je weer verder gaat met de verb. Dit gaat met suspend(xx) Waar xx het aantal seconden is wat je wilt wachten. Ook suspend(0) heeft effect. Dit kun je gebruiken in verbs die veel ticks eisen weer even op adem te laten komen.


effe tussendoor: lijsten



Je weet al wat strings zijn. Maar je hebt nog wat leuks tot je beschikking, namelijk de lijsten. Een lijst is een verzameling die van alles kan bevatten. Zoals een string tussen "" staat, zo staat een lijst tussen {}. Elementen uit de lijst worden gescheiden door een komma.

Een aantal voorbeelden van lijsten:

Om een element uit een lijst te halen moet je het element nummer tussen [] zetten (net als bij strings overigens):

Handige lijsten om te weten zijn:

Vraag ook eens help op over listappend, listinsert en listdelete.

Veel voorkomende fout:

mijnlijst = {"b", "l", "a"};
listdelete(mijnlijst, 1);
player:tell(tostr(@mijnlijst); 
Op het eerste gezicht zou dit "la" opleveren. Echter, in de 2e regel gebeurt niet veel. Het resultaat is namelijk wel {"l", "a"} maar dit wordt nergens aan toegekend. Het programma moet er dus zo uitzien:
mijnlijst = {"b", "l", "a"};
mijnlijst = listdelete(mijnlijst, 1);
player:tell(tostr(@mijnlijst);
Om een hele lijst uit z'n voegen te trekken gebruik je het @ teken, je moet daarna echter wel meteen wat doen met de losse elementen, bijvoorbeeld naar een string omzetten of in een nieuwe lijst verwerken:

Om te kijken of iets een element is van een lijst gebruik je in:

De lengte van een lijst kan je opvragen met length(lijst):

Even wat voorbeelden:
lijst = {};
tel = 1;
while (tel < 10)
  lijst = {@lijst, tel};
  tel = tel + 1;
endwhile
player:tell(tostr(@lijst));
Deze verb begint met een lege lijst en voegt daar 10 keer een element aan toe.
if (#2 in connected_players())
  #2:tell("Hoi, leuk dat je er bent!");
endif
Deze spreekt voor zich.


for



Dan zijn we nu bij de for-constructie gekomen. Meteen maar een voorbeeldje:
alfabet = {"a", "b", "c", "d", "e", "f"};
for abc in (alfabet)
  player:tell(abc);
endfor
Alles binnen de for-lus wordt net zoveel keer aangeroepen als er elementen in de lijst zijn. In dit voorbeeld verandert de variabele abc bij elke nieuwe aanroep in respectievelijk "a", "b", "c", "d", "e" en "f".

Nog een voorbeeld:

wiezijner = "";
for zoek in (connected_players())
  wiezijner = ((wiezijner + zoek.name) + ",");
endfor
wiezijner[length(wiezijner)] = ".";
player:tell("De volgende personen zijn aanwezig:");
player:tell(wiezijner);
Geeft een beetje lelijke output, maar het gaat om het idee. Kijk ook eens naar de 5e regel, daar wordt op een slimme manier de laatste komma door een punt vervangen.


tijd voor iets algemeens



Zoals je moet weten is de hele structuur van de metro object-georienteerd. Bijna elk object stamt wel af van een ander object. Doe bijvoorbeeld: @ouders hier.

Wat is er leuker om zelf een generiek object te maken, waar anderen weer afstammelingen van kunnen maken? Tsja.. ik kan genoeg dingen bedenken die leuker zijn, maar daar is deze handleiding niet voor bedoeld.

Als je iets generieks gaat maken, houdt het dan zo generiek mogelijk. Ga dus niet een generieke kaas-souffle (met streepie op de e) maken, maar denk meer aan generiek etenswaar. Een simpel voorbeeld:

@maak $ding genaamd "generiek eetfrutsel":frutsel
@beschrijf frutsel als Je ziet iets eetbaars.
@verb frutsel:eet this

Doe nu @edit frutsel:eet en schrijf het volgende programma:

player:tell("Je neemt een hap van ", this.name, ".");
player.location:announce(player.name, " neemt een hap van ", this.name, ".");

Zorg nu dat je dit object vruchtbaar (fertile) maakt met:

@chmod frutsel +f

Iemand anders kan nu een afstammeling maken van je frutsel:

@maak frutsel genaamd "een overheerlijke kruisbessentaart",taart
(altijd nog beter dan bosbessentaart!)

Let op: Zorg goed voor je generieke objecten. Laat ze niet zomaar rondslingeren en wees voorzichtig met wijzigingen. Laten we een kleine uitbreiding maken op onze frutsel:

@property frutsel.grootte 3

En verander de eet-verb:

if (this.grootte)
  player:tell("Je neemt een hap van ", this.name, ".");
  player.location:announce(player.name, " neemt een hap van ", this.name, ".");
  this.grootte = this.grootte - 1;
else
  player:tell(this.name, " is al helemaal opgegeten!");
endif
Welnu... alles is okee denk je. Maar dat valt even tegen. D'r komt iemand langs en die maakt een afstammeling van je frutsel. Hij is heel blij en probeert d'r een hap van te nemen.

Maar dan... hij krijgt allemaal vage errors op zijn scherm! Dit komt omdat deze speler de eigenaar is van de property .grootte, maar jij bent nog steeds de eigenaar van de verb eet.

Als hij die verb aanroept, dan vraagt-ie dus eigenlijk aan jou om de property .grootte te veranderen, maar jij hebt helemaal geen recht om aan iemand anders zijn properties te zitten!

Je wilt dus dat bij het maken van een afstammeling dat de properties van de afstammeling ook van jou blijven, zodat jouw verbs die erop staan deze zonder problemen kunnen wijzigen. Dit gaat door middel van:

@chmod frutsel.grootte -c

Vanaf nu blijf je lekker zelf de eigenaar de property .grootte van afstammelingen van je frutsel.


adetails



Een property waar nogal veel vragen over zijn. Hier de volledige uitleg! Wanneer de object:look_self aangeroepen wordt, dus bijvoorbeeld wanneer je kijk <object> doet, dan wordt de inhoud van de .adetails property aan de speler verteld (en nog wat meer, maar daar hebben we het even niet over).

Elk object in de metro heeft een verb adetail. Met deze verb kan een detail toegevoegd worden op een object. Dit komt dan weer in de .adetails property terecht.

Bij het toevoegen van een adetail, moet een lijst met 2 of 3 dingen worden meegegeven. De lijst bestaat als eerste uit het soort adetail in de vorm van een getal. Als tweede geef je de beschrijving in de vorm van een string. Als je gebruik maakt van het soort 1 of 3 (zie beneden), dan moet je nog een derde element in de lijst zetten. Deze derde is de tijd dat de adetail uitgewerkt is en dus uit de .adetail property gehaald wordt.

Deze tijd wordt opgegeven in het aantal secondes vanaf de jaarwisseling van het jaar 1970. Tsja, zo zit dat nou eenmaal in de MOO... dat heb ik ook niet verzonnen. Met de verb time() kan je het aantal seconden opvragen, dat verstreken is sinds dat moment.

Hier volgt een opsomming van de soorten adetails die worden gebruikt:

Een voorbeeld van het toevoegen van een adetail op iemand:

@maak $ding genaamd "een geheimzinnig knopje", knopje, knop
@verb knopje:druk this none none
@edit knopje:druk

En voer het volgende programma in:

player:tell("Je drukt op het knopje...");
player.location:announce(player.name, " drukt op het knopje.");
suspend(4);
player:tell("Opeens valt er een hele emmer water over je heen!");
player.location:announce("Er valt een emmer water op ", player.name, "!");
player:adetail({1 , player.ppc + " kleren zijn nat!", time() + 600});
Als je nu druk knopje intikt en naar jezelf kijkt, dan zie je dat je kleren nat zijn. Na 600 seconden zal die tekst weer verdwenen zijn.

Maar stel nu dat je soort 2 had gebruikt, dan loop je voor altijd met natte kleren rond. Dat is ook niet zo leuk, dus zijn er 2 manieren om adetails te verwijderen.

Met clean_this kan je de soorten 1 en 2 verwijderen. Met medic_this kan je de soorten 3 en 4 verwijderen.

Voorbeeld:

@verb me:eersteweg
@edit me:eersteweg

if (player.adetails == {})
  player:tell("Er staan geen adetails op je");
else
  eerste = player.adetails[1];
  if (eerste[1] in {1, 2})
    player:clean_this(eerste);
    player:tell("Eerste afwasbare adetail weggehaald.");
  elseif (eerste[1] in {3, 4})
    player:medic_this(eerste);
    player:tell("Eerste lichamelijke adetail weggehaald.");
  else
    player:tell("Sorry, je kan je eerste adetail niet verwijderen.");
  endif
endif
Soort nummer 6 wordt gebruikt door generieke kleding. Op de player staan de verbs trek_aan en trek_uit. Deze verbs hoef je alleen maar de tekst mee te geven. Zo kun je dus de bovenste verb uitbreiden:

if (player.adetails == {})
  player:tell("Er staan geen adetails op je");
else
  eerste = player.adetails[1];
  if (eerste[1] in {1, 2})
    player:clean_this(eerste);
    player:tell("Eerste afwasbare adetail weggehaald.");
  elseif (eerste[1] in {3, 4})
    player:medic_this(eerste);
    player:tell("Eerste lichamelijke adetail weggehaald.");
  elseif (eerste[1] == 6)
    player:trek_uit(eerste[2]);
    player:tell("Eerste kledingstuk uitgetrokken.");
  else
    player:tell("Sorry, je kan je eerste adetail niet verwijderen.");
  endif
endif

dat was het weer



Zo, ik hoop dat deze handleiding jullie weer een jaartje zoet zal houden. Mochten d'r nog dingen in m'n hoofd opkomen waar ik wel weer een paar honderd regeltjes over kan volschrijven, dan doe ik dat nog wel een keer. Maar voorlopig moet je zelf maar weer flink dingen uitzoeken...

En als je problemen hebt kun je altijd bij een hulpvaardige bouwvakker terecht! En (zucht...) als het echt niet anders kan bij een opperbouwvakker.