! physics.h !----- ! Version 1.2 /by\ Mike Tulloch /in\ Feb '05 ! Thanks to Dan Shiovitz for paving the way, ! and thanks to Sam Hulick for making it all possible. ! ! Changes: ! 1) Updated routines for Inform 6.30 ! 2) Added PHY_SUGGEST constant, which allows you to turn ! suggestions if a container is too full/heavy on or off. ! 3) Updated comments ! ! Set the PHY_SUGGEST constant before you include "Physics.h". ! Set it to 1 or higher to allow suggestions; set it to 0 to disallow them. ! ! Questions, bugs, praise, email me at poster@aurora.cotse.net. :) !----- ! Version 1.1 ! by Sam Hulick ! This is a slight revision (not by much) of the old physics.inf example ! I released quite awhile ago. Please read through these comments here ! so you know exactly how it works. ! P.S.: I give Graham Nelson complete permission to add this into ! his next library release. ! When creating a game using physics.h, you must define a new player ! object so it includes a 'max_space 100', in it, preferably near the ! 'capacity 100'. ! ! Do *NOT* use the ChangePlayer() routine, as that is intended only ! for changing the player during play. ! ! Do define a player object somewhere before Initialise() like this: ! Object newplayer ! with ! max_weight 100, !-- Or whatever you like ! max_space 100, !-- Or whatever you like ! description " "; !-- Put description here if you like ! ! Then after Initialise(), include the following lines: ! player = newplayer; ! give player transparent concealed animate proper; ! ! location=first_room_of_game; !-- whatever it is ! ! Note that max_weight and max_space do NOT work on an object-by-object ! basis, but by weight #'s. That's the whole point of physics.h. ! Inform's capacity handling routines aren't very detailed, in that you ! could put three large rocks in a bag, and the bag will be full, but ! if you put three small pebbles in the bag, it is strangely full as ! well. This file will remedy that problem. When you define objects, ! give it a 'weight' and 'size', i.e. ! ! Object skull "human skull" ! with name "human" "skull", ! weight 8, ! size 6, ! ... ! ! Just figure a decent weight/size scale for your game, and think of ! what size or weight you would give it. I would give a shovel a ! weight of 10 or 13, perhaps, and a size of 15-20, maybe. It's ! just estimating. I give very small objects (pebbles, M&M's, etc.) ! a weight and size of 0, usually, because they're so small. Or ! you could up-scale your system, making M&M's size/weight both 1, ! then your shovel would more likely have a weight of 30, since you've ! up-scaled your values to compensate for the M&M's. There are no ! rights or wrongs: it's your game. I'm just providing the medium ! to control these weights and sizes. ! Now, on to more technical things. max_weight and max_space are ! used for containers and supporters. They can be values or ! routines (maybe for magical containers that expand). I think ! that is self-explanatory. ! too_big and too_heavy are a bit more complicated. They can simply ! be a string to print to the user when an object is too heavy or ! big to carry, or it can be a routine if you wish. But on a supporter ! or container, it really MUST be a routine. When too_heavy or too_big ! is called, 'action' contains either ##Take, ##PutOn, or ##Insert. ! Let's give an example: ! Object mcont "magic container" ! with description "You can put things on or in it, ooh.", ! name "magic" "container", ! size 5, ! weight 10, ! max_weight 30, ! max_size 30, ! too_heavy [; ! switch (action) ! { ! ##Take: "The container contains too many heavy things \ ! for you to handle it."; ! ##PutOn: "However magical it is, it can't support the \ ! weight of that."; ! ##Insert: "That object is too heavy, the magical \ ! container would rip trying to carry that."; ! } ! ], ! ..... ! ! And too_big works the same way, only it deals with the fact that ! the container can't handle the size of an object. If these things ! are unclear to you, you can skim through this file and read the ! source code. If you do not provide a too_heavy/too_big routine ! or string for an object, default messages will be printed, and ! you don't have to handle examining the 'action' variable. But ! you will most likely want to handle it yourself, since the default ! messages are.. well.. rather bland. !-- Also, the default messages refer to "you", and not to the object, !-- So you must redefine them for containers and supporters. ! P.S.: Don't forget to REPLACE AttemptToTakeObject, InsertSub, and ! PutOnSub and include this file after parser and verblib. Property max_weight alias capacity; ! max weight something can hold Property max_space; ! max space..... Property weight; ! can be a routine. so can max_weight/max_space Property size; ! same for this one Property too_heavy "That's too heavy for you to carry right now."; Property too_big "That's too big for you to carry right now."; ! can the carrier take on the weight of obj? true/false return value [ OkWeight carrier obj w; w = ValueOrRun(obj, weight); if ((WeightCarried(carrier) + w) > ValueOrRun(carrier, max_weight)) rfalse; rtrue; ]; ! can the carrier take on the size of obj? [ OkSize carrier obj s; s = ValueOrRun(obj, size); if ((SpaceCarried(carrier) + s) > ValueOrRun(carrier, max_space)) rfalse; rtrue; ]; [ WeightCarried obj o total; objectloop (o in obj) { total = total + ValueOrRun(o, weight); if (child(o) ~= 0) total = total + WeightCarried(o); } return total; ]; [ SpaceCarried obj o total; objectloop (o in obj) total = total + ValueOrRun(o, size); return total; ]; !! The reason SpaceCarried() isn't recursive is because it merely doesn't ! have to be. WeightCarried() must be recursive, because if you put a ! huge heavy steel ball into a light sack and carry the sack, this doesn't ! mean the sack relieves your weight. However, if you can manage to fit a ! very large object into a small sack, then your troubles are reduced. (a ! good example would be a huge Nerf(TM) beachball that is tough to carry ! around, but if you find a small, light box, you can open the box, stuff ! the Nerf(TM) ball into it, and close the box. The weight carried is ! still the box plus the ball, but now your space carried has reduced. [ AdviseMoveIt obj; print "Try moving some things off ", (the) obj; "."; ]; [ AdvisePullIt obj; print "Try removing some things from ", (the) obj; "."; ]; !-- Updated in version 1.2 !-- Dropped in AttemptToTakeObject for RTakeSub [ AttemptToTakeObject item ancestor after_recipient i j k a rval; ! Try to transfer the given item to the player: return false ! if successful, true if unsuccessful, printing a suitable message ! in the latter case. ! People cannot ordinarily be taken. if (item == player) return L__M(##Take, 2); if (item has animate) return L__M(##Take, 3, item); ancestor = CommonAncestor(player, item); if (ancestor == 0) { i = ObjectScopedBySomething(item); if (i ~= 0) ancestor = CommonAncestor(player, i); } ! Is the player indirectly inside the item? if (ancestor == item) return L__M(##Take, 4, item); ! Does the player already directly contain the item? if (item in player) return L__M(##Take, 5, item); ! Can the player touch the item, or is there (e.g.) a closed container ! in the way? if (ObjectIsUntouchable(item, false, true)) return; ! The item is now known to be accessible. ! Consult the immediate possessor of the item, if it's in a container ! which the player is not in. i = parent(item); if (i ~= ancestor && (i has container || i has supporter)) { after_recipient = i; k = action; action = ##LetGo; if (RunRoutines(i, before) ~= 0) { action = k; rtrue; } action=k; } if (item has scenery) return L__M(##Take, 10, item); if (item has static) return L__M(##Take, 11, item); ! The item is now known to be available for taking. Is the player ! carrying too much? If so, possibly juggle items into the rucksack ! to make room. k = 0; objectloop (j in player) if (j hasnt worn) k++; !-- 1.2 Is the item too heavy to be carried? if (OkWeight(player, item) == 0) { a = action; action = ##Take; rval = PrintOrRun(item, too_heavy, 0); action = a; return rval; } !-- 1.2 just the original code here follows for this if. !-- Is object too large for player to carry? if (OkSize(player, noun) == 0) { if (SACK_OBJECT~=0) { if (parent(SACK_OBJECT)~=player) return ObjTooBig(noun); j=0; objectloop (k in player) if (k~=SACK_OBJECT && k hasnt worn && k hasnt light) j=k; if (j~=0) { L__M(##Take,13,j); keep_silent = 1; ; keep_silent = 0; if (j notin SACK_OBJECT) rtrue; } else return ObjTooBig(noun); } else return ObjTooBig(noun); } if (k >= ValueOrRun(player, capacity)) { if (SACK_OBJECT ~= 0) { if (parent(SACK_OBJECT) ~= player) return L__M(##Take, 12); j = 0; objectloop (k in player) if (k ~= SACK_OBJECT && k hasnt worn && k hasnt light) j = k; if (j ~= 0) { L__M(##Take, 13, j); keep_silent = 1; ; keep_silent = 0; if (j notin SACK_OBJECT) rtrue; } else return L__M(##Take, 12); } else return L__M(##Take, 12); } ! Transfer the item. move item to player; ! Send "after" message to the object letting go of the item, if any. if (after_recipient ~= 0) { k = action; action = ##LetGo; if (RunRoutines(after_recipient, after) ~= 0) { action = k; rtrue; } action=k; } rfalse; ]; [ ObjTooBig obj a rval; a = action; action = ##Take; rval = PrintOrRun(obj, too_big, 0); action = a; return rval; ]; !-- 1.2 : Added a to routine and added tests for PHY_SUGGEST [ PutOnSub ancestor a; receive_action = ##PutOn; if (second == d_obj || player in second) <>; if (parent(noun) == second) return L__M(##Drop,1,noun); if (parent(noun) ~= player) return L__M(##PutOn, 1, noun); ancestor = CommonAncestor(noun, second); if (ancestor == noun) return L__M(##PutOn, 2, noun); if (ObjectIsUntouchable(second)) return; if (second ~= ancestor) { action = ##Receive; if (RunRoutines(second, before) ~= 0) { action = ##PutOn; return; } action = ##PutOn; } if (second hasnt supporter) return L__M(##PutOn, 3, second); if (ancestor == player) return L__M(##PutOn, 4); if (noun has worn) { L__M(##PutOn, 5, noun); ; if (noun has worn) return; } !-- Is item small enough to fit on second? !-- Original routine if (OkSize(second, noun) == 0) { a = action; action = ##PutOn; if (RunRoutines(second, too_big) == 0) { ! default message print_ret (The) noun, " won't fit on ", (the) second, "."; } action = a; if ((ValueOrRun(noun, size) <= ValueOrRun(second, max_space)) && PHY_SUGGEST) return AdviseMoveIt(second); rtrue; } !-- Is item light enough to put on the second? !-- Original routine. if (OkWeight(second, noun) == 0) { a = action; action = ##PutOn; if (RunRoutines(second, too_heavy) == 0) { print_ret "You feel ", (the) second, " begin to give as you start to put ", (the) noun, " on it. Maybe this isn't such a good idea."; } action = a; if ((ValueOrRun(noun, weight) <= ValueOrRun(second, max_weight)) && PHY_SUGGEST) return AdviseMoveIt(second); rtrue; } if (children(second) >= ValueOrRun(second, capacity)) return L__M(##PutOn, 6, second); move noun to second; if (AfterRoutines() == 1) return; if (second ~= ancestor) { action = ##Receive; if (RunRoutines(second, after) ~= 0) { action = ##PutOn; return; } action = ##PutOn; } if (keep_silent == 1) return; if (multiflag == 1) return L__M(##PutOn, 7); L__M(##PutOn, 8, noun); ]; !-- 1.2: Added a to the routine, and added PHY_SUGGEST tests. !-- all else is unchanged. [ InsertSub ancestor a; receive_action = ##Insert; if (second == d_obj || player in second) <>; if (parent(noun) == second) return L__M(##Drop,1,noun); if (parent(noun) ~= player) return L__M(##Insert, 1, noun); ancestor = CommonAncestor(noun, second); if (ancestor == noun) return L__M(##Insert, 5, noun); if (ObjectIsUntouchable(second)) return; if (second ~= ancestor) { action = ##Receive; if (RunRoutines(second,before) ~= 0) { action = ##Insert; rtrue; } action = ##Insert; if (second has container && second hasnt open) return L__M(##Insert, 3, second); } if (second hasnt container) return L__M(##Insert, 2, second); if (noun has worn) { L__M(##Insert, 6, noun); ; if (noun has worn) return; } if (children(second) >= ValueOrRun(second, capacity)) return L__M(##Insert, 7, second); if (OkSize(second, noun) == 0) { a = action; action = ##Insert; if (RunRoutines(second, too_big) == 0) { print_ret "There's not enough room inside."; } action = a; if ((ValueOrRun(noun, size) <= ValueOrRun(second, max_space)) && PHY_SUGGEST) return AdvisePullIt(second); rtrue; } if (OkWeight(second, noun) == 0) { a = action; action = ##Insert; if (RunRoutines(second, too_heavy) == 0) { print_ret (The) second, " won't hold anymore weight."; } action = a; if ((ValueOrRun(noun, weight) <= ValueOrRun(second, max_weight)) && PHY_SUGGEST) return AdvisePullIt(second); rtrue; } move noun to second; if (AfterRoutines() == 1) rtrue; if (second ~= ancestor) { action = ##Receive; if (RunRoutines(second, after) ~= 0) { action = ##Insert; rtrue; } action = ##Insert; } if (keep_silent == 1) rtrue; if (multiflag == 1) return L__M(##Insert, 8, noun); L__M(##Insert, 9, noun); ];