Anyone have any issues compiling the ConSpace library (specifically ConSpace2/Space_un_us.t), under linux/t3make? All other components seem to compile fine, or at least without coredump. Have already tried dos2unix, and internal syntax triangulation has not yielded fruit yet. My gut says it is most likely more of this: TADS Won’t Compile, but thought I’d ask before I start line-by-lining it.
I looked at using ConSpace2 and didn’t run into any problems either compiling the test game or compiling it against my own code (although I subsequently decided to not use it).
Just for reference, here’s a scrap of nonsense I put together when I was looking at it, implementing an annoying-to-navigate road location:
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
roadGroup: SpaceConnector;
roadGroupNorth: roadGroup;
roadGroupSouth: roadGroup;
class RoadRoom: Room
connectionGroup = [ roadGroup ]
actorInPrep = 'on'
actorIntoPrep() {
if(gActor.locationBefore.getOutermostRoom.ofKind(RoadRoom))
return('over to');
else
return('onto');
}
;
class RoadRoomNorth: RoadRoom
connectionGroup = [ roadGroupNorth ]
north = northRoad
east = northeastSidewalk
west = northwestSidewalk
;
class RoadRoomSouth: Room
connectionGroup = [ roadGroupSouth ]
south = southRoad
east = southeastSidewalk
west = southwestSidewalk
;
// North part of downtown
northRoadMain: RoadRoomNorth 'North End Of Downtown' 'north end of downtown' 'm
iddle of the road'
"This is a road running north and south. The road is flanked to
the east and west by shops. "
south = southRoadMain
;
+me: Person;
+pebble: Thing 'small round pebble' 'pebble'
"A small, round pebble. "
;
northeastSidewalk: RoadRoomNorth 'Northeast Sidewalk'
"This is the sidewalk to the east of the road. The Northeast Shop is
just to the east, and the Northwest Shop is across the road to the
west. "
south = southeastSidewalk
west = northwestSidewalk
east = northeastShop
;
northwestSidewalk: RoadRoomNorth 'Northwest Sidewalk'
"This is the sidewalk to the west of the road. The Northwest Shop is
just west of here, and the Northeast Shop is off to the east, across
the road. "
south = southwestSidewalk
east = northeastSidewalk
west = northwestShop
;
northeastShop: Room 'Northeast Shop'
"This is the Northeast Shop. The only exit is to the west. "
west = northeastSidewalk
;
northwestShop: Room 'Northwest Shop'
"This is the Northwest Shop. A doorway east opens onto the sidewalk. "
east = northwestSidewalk
;
// South part of downtown
southRoadMain: RoadRoomSouth 'South End Of Downtown' 'south end of downtown' 'middle of the road'
"This is a road running north and south. The road is flanked to
the east and west by shops. "
north = northRoadMain
;
southeastSidewalk: RoadRoomSouth 'Southeast Sidewalk'
"This is the sidewalk to the east of the road. The Southeast Shop is
just to the east, and the Southwest Shop is across the road to the
west. "
north = northeastSidewalk
west = southwestSidewalk
east = southeastShop
;
southwestSidewalk: RoadRoomSouth 'Southwest Sidewalk'
"This is the sidewalk to the west of the road. The Southwest Shop is
just west of here, and the Southeast Shop is off to the east, across
the road. "
north = northwestSidewalk
east = southeastSidewalk
west = southwestShop
;
southeastShop: Room 'Southeast Shop'
"This is the Southeast Shop. The only exit is to the west. "
west = southeastSidewalk
;
southwestShop: Room 'Southwest Shop'
"This is the Southwest Shop. A doorway east opens onto the sidewalk. "
east = southwestSidewalk
;
// Outside of downtown
northRoad: Room 'North Road'
"This is the north road. Everything interesting is south of here. "
south = northRoadMain
;
southRoad: Room 'South Road'
"This is the south road. Downtown, such as it is, lies to the north. "
north = southRoadMain
;
versionInfo: GameID
name = 'sample'
byline = 'nobody'
authorEmail = 'nobody <foo@bar.com>'
desc = '[This space intentionally left blank]'
version = '1.0'
IFID = '12345'
;
gameMain: GameMainDef
initialPlayerChar = me
;
…which compiles with…
-D LANGUAGE=en_us
-D MESSAGESTYLE=neu
-Fy obj -Fo obj
-o game.t3
-lib system
-lib adv3/adv3
-lib ../extensions/ConSpace2/ConSpace
-source sample
…and seems to run fine:
North End Of Downtown
This is a road running north and south. The road is flanked to the east and
west by shops.
You see a pebble here.
>w
You walk over to the northwest sidewalk.
>l
Northwest Sidewalk
This is the sidewalk to the west of the road. The Northwest Shop is just west
of here, and the Northeast Shop is off to the east, across the road.
On the middle of the road, you see a pebble.
Thanks for the quick confirmation. It is definitely more of THIS
For whatever reason, it coredumps on any VerbRule
statements, new, replace or modifies. When I cut all of those statements and paste into another, currently compiling, file the whole mess builds just fine. Interesting that only VerbRule
seems vulnerable. Will probe further after I decide if I want ConSpace or not…
Doesn’t appear to be VerbRules
in general with ConSpace2.
I just tacked this onto the “demo” above:
DefineSystemAction(Foozle)
execAction() {
defaultReport('A hollow voice says <q>This space intentionally
left blank.</q> ');
}
;
VerbRule(Foozle)
'foozle' : FoozleAction
verbPhrase = 'foozle/foozling'
;
…and it works fine:
North End Of Downtown
This is a road running north and south. The road is flanked to the east and
west by shops.
You see a pebble here.
>w
You walk over to the northwest sidewalk.
>l
Northwest Sidewalk
This is the sidewalk to the west of the road. The Northwest Shop is just west
of here, and the Northeast Shop is off to the east, across the road.
On the middle of the road, you see a pebble.
>foozle
A hollow voice says "This space intentionally left blank."
Still no daylight on my local compilation problem, but works fine with chopped up source files. Wanted to document some usability fixes I needed to make. I was primarily engaging to take advantage of Enterable ComplexContainers (ECContainer in the module’s parlance). I noticed two behaviors that seemed slightly off:
-
When attempting to get in/on/under/behind anything forbidden, the error message was
You cannot stand {in/on/behind/under} that.
Even for>SIT BEHIND
,>LIE UNDER
etc The appropriate sit/lie error messages are provisioned in the code. -
When attempting to
>WALK OVER TO SOMEOBJ
in a room without a definedconnectionGroup
, you got the standardThe someobj is too far away.
error message. Even though you are in the same room with SOMEOBJ. (Note, without a true ConSpace implementation,>WALK OVER TO
doesn’t do much, but according to my sensibilities it shouldn’t FAIL with deceptive message.)
Both issues I traced to the new verifyStandClose
method in ConSpace.t
Locally hacked fixes below:
verifyStandClose(pos, post)
{
local locProp = whichLocProp(pos);
if(self.(locProp) == nil) {
// (1) Modified to get sit/stand/lie messaging correct - JJMcC
//
//illogical(&cannotStandCloseMsg, pos); // original code
switch(post) {
case sitting:
illogical(&cannotSitCloseMsg, pos);
break;
case lying:
illogical(&cannotLieCloseMsg, pos);
break;
default:
illogical(&cannotStandCloseMsg, pos);
break;
}
}
if(gActor.isIn(self.(locProp))
&& !gActor.roomLocation.ofKind(NestedRoom)
&& gActor.posture == post)
illogicalAlready(&actorPostureThereMsg, self, pos);
/* Don't allow this kind of travel to occur unless
* the object is within the same connectionGroup
* as the actor, and autoApproach is allowed (true)
* for this object, unless the actor is in one of the
* locations specified in my extraApproachRooms list.
*/
/* Also allow if in same room! JJMcC */
if (((gActor.CSGetOutermostRoom.connectionGroup == nil
|| !inSameConnectionGroup(gActor)
|| !autoApproach)
&& extraApproachRooms.indexOf(gActor.CSGetOutermostRoom) == nil)
// (2) Needed to add test for same room, as otherwise fails here without
// defined connectionGroup! - JJMcC
&& (!gActor.isIn(self.(locProp))))
illogical(&tooDistantMsg, self);
}
Other than these glitches, ECContainers do pretty much exactly what I wanted, and even without a true ConSpace implementation, the new verbs are nicely flexible. Think I still prefer Open Door Patterns as lighter to customize than ConSpace’s SpaceConnectorDoor
. Though this could just be sunk cost fallacy.
And another one, though I’ll grant this one is in the weeds a bit. My situation is this: I have a room, in which is a large stage, modeled as three platforms (which the PC can freely traverse): Upstage, StageRight and StageLeft. On this, I have a very large-bodied Multi-Loc NPC who occupies all three platforms.
Meaning the location nesting for the NPC we’ll call “JollyGreen” is
JollyGreen->BigBody(multiLoc)->All 3 Stages->TheatreRoom
To interact with JollyGreen, the PC must pass the canTalkToObj
precondition, which ConSpace.t modifies:
modify canTalkToObj
checkPreCondition(obj, allowImplicit)
{
local actionAttempted = nil;
if(!obj.CSGetOutermostRoom.allowRemoteConversation
&& obj.CSGetOutermostRoom != gActor.CSGetOutermostRoom)
{ // fail cases & etc
They can talk, as long as CSGetOutermostRoom shows the same for both of them, in this case TheatreRoom.
CSGetOutermostRoom is defined twice. Once for baseline Thing, and overridden for MultiLocs. For Thing, it recurses up the location tree until it finds the top.
modify Thing
/* In most cases, CSGetOutermostRoom() should behave just like the
* normal getOutermostRoom(). But if there's an intervening multiLoc,
* in the containment tree, we will perform a search based on gActor's
* location, and we will return the multiLoc's SCGetOutermostRoom,
* which is the location in the multiLoc's locationList that is
* nearest the gActor. (Normally, because multiLoc has no location
* property, multiLoc returns 'self' for its outermost room.)
*/
CSGetOutermostRoom() {
return (location ? location.CSGetOutermostRoom() : self);
}
/* Modify MultiLoc so that CSGetOutermostRoom returns the room in its
* locationList which is nearest to gActor's location.
*
* If for whatever reason no such path is found, return locationList[1]
* (or nil if we have no locationList).
*/
modify MultiLoc
CSGetOutermostRoom()
{
if(gActor) {
local path = CSPathfinder.findPath(gActor, self);
if(path && path.length())
return path[path.length()];
}
return (locationList && locationList.length() ? locationList[1] : nil);
}
;
The issue is that the recursion stops at MultiLoc, it simply returns closest or first of the locationList. In the example above, gActor.CSGetOutermostRoom()
will return Theatre, while jollyGreen.CSGetOutermostRoom()
returns StageRight (say). Because they are different, this fails the canTalkToObj
precondition and they can’t talk!
The fix is to restore recursion if the multiLoc’s location itself has a location.
/* JJMcC - need to continue location recursion if Multiloc is not 'top level'
*/
modify MultiLoc
CSGetOutermostRoom()
{
if(gActor) {
local path = CSPathfinder.findPath(gActor, self);
if(path && path.length())
// return path[path.length()]; // orig, non-recursive code
// instead, continue recursion if .location exists
//
return (path[path.length()].location ?
path[path.length()].location.CSGetOutermostRoom()
: path[path.length()]);
}
// same for default case, replace orig code below
// return (locationList && locationList.length() ? locationList[1] : nil);
//
if (!(locationList && locationList.length())) return nil;
return (locationList[1].location ?
locationList[1].location.CSGetOutermostRoom() : locationList[1]);
}
;
I didn’t use con space in my game, but I dig figuring this kind of stuff out.
An adv3 bug I never took the time to fix, because I was much newer to TADS when I had to resolve it: you can’t make a Container a MultiLoc without stack overflow. Probably a simple tweak of isIn(), but I never revisited it…