Argax Project

Node Status: ROUGH

Appendix 1: Example Scene: PC_Unconscious

Chapter V describes the scene PC_Unconscious as an example of a scene's internal complexity. As a longer example, the following is the original Inform code for this scene.

!! Scene: PC_Unconscious
!!
!! The PC succumbs to injuries that prove non-fatal.
!!
!! > MEvent(attacker: PC_Unconscious[?], PC, rescuer?, ?)
!!
!! The PC will recover consciousness in various states depending
!! on who knocked her unconscious in the first place.  The _detail_
!! will indicate the nature the event: +1 is an active rescuing, 0 is
!! neutral (no rescue possible), -1 is an imprisonment, and -2 is a
!! betrayal (left behind).  The LOOK event contained within this event will
!! give the awakening location.
!!
!! Pre:
!! * An Attack on PC
!! * PC is incapacitated at 0 health.
!! * (But usually invoked directly as an interruption by <DT_PC_Falls_Inactive>)
!!
!! Play:
!! First, heals PC back to 2 health and advances the <DemeterTime> by one.
!!
!! If attacker was a passenger NPC:
!! That NPC disarms the PC (if armed).
!!
!! If PC was in the gondola or observation deck, the PC will then wake on 
!! the locked observation deck.
!!
!! Otherwise, depends on surrounding NPCs.  If at least one has a positive
!! _average(morality, affinity(PC))_, this "rescuer" will have dragged the
!! PC back to obs deck.  However, if no one cares enough about the PC,
!! she'll wake up where she fell (probably locked out: any GoParty will
!! advance silently until it has returned).
!!
!! If attacker was Revenant:
!! If no NPCs around, this becomes <PC_Dies>.  Otherwise, the revenant
!! gets another offscreen <Revenant_Acts>.  If there is still an NPC
!! standing, then will check affinity/morality and proceed accordingly,
!! as described above.  If a rescuer is found, PC will wake in gondola in
!! their bunk.  Rescuer will be there to narrate what happened.
!!
!! Import 4; Imperative 9.
!!
MMiddleScene PC_Unconscious
  with
    import 4,
    imperative 9,

    cause nothing,

    canPlay [;
      if (DCharacter__PC.health == 0 && DCharacter__PC has incapacitated) {
        self.cause = MEventHistory.find(0, nothing, nothing, DV_ATTACK,
                                          DCharacter__PC);
        if (self.cause) {
          return MList__new(self.cause);
        }
      }
    ],

    !! Method: getRescuer(victim, bystanders)
    !!
    !! Looks through the list of <DNPC> _bystanders_ for the NPC with
    !! the highest _average(morality, affinity(victim))_.  Returns
    !! said NPC, or nothing if no one has an average > 0.
    !!
    getRescuer [ victim bystanders
      i len npc moral aff highest highestNPC;

      highest = 0;  !needs to be at least higher than this
      highestNPC = nothing;

      len = bystanders.size();
      for (i = 0 : i < len : i++) {
        npc = bystanders.get(i);
        moral = npc.morality.getValue();
        aff = (npc.affinities-->victim.affIndex).getValue();
        aff = (moral + aff) / 2;
        if (aff > highest) {
          highest = aff;
          highestNPC = npc;
        }
      }
      return highestNPC;
    ],

    !PLAY
    play [event
      witnesses i sub npc wakeIn disarmedOf hooks deckers;

      event.actress = self.cause.actress;
      event.dirObj = DCharacter__PC;
      witnesses = DNPC__GetActive();

      if (event.actress == Revenant) {
        if (witnesses.size()) {
          npc = witnesses.get(random(witnesses.size()) - 1);
          !revenant gets another action while everyone else tries to respond
          event.add(Revenant_Attacks.playAt(event.loc, true, npc));  !play silently
          if (npc.health <= 0) {
            !that npc just fell too
            witnesses.remove(witnesses.indexOf(npc));
          }
        }
        if (witnesses.size()) {
          !still someone standing that might save you
          event.secondObj = self.getRescuer(DCharacter__PC, witnesses);
        }else {
          !left alone with Revenant: PC_Dies
          MList.destroy(witnesses);
          sub = MEvent__new(DCharacter__PC, PC_Dies, nothing,
                             nothing, self.cause, event.loc);
          hooks = Ending_Hooks.getHooks();
          sub.predicate.play(sub);
          if (hooks) {
            !manual/lazy/play-time reinc
            sub.reincorporates.join(hooks);  !destroys hooks
          }
          event.add(sub);
          event.detail = 0;
          return;
        }

        if (event.secondObj) {
          !will be dragged back to safety.  Even if already in gondola.
          wakeIn = YourBottomBunk;
          event.detail = 1;
        }else {
          !will be left behind
          wakeIn = event.loc;
          event.detail = -2;
        }

      }else {
        !attacked by an NPC

        !remove any weapons from player (but can't remove from objectloop)
        disarmedOf = MList.create();
        objectloop (i in player) {
          if (i ofclass DWeapon) {
            disarmedOf.add(i);
          }
        }
        for (i = 0 : i < disarmedOf.size() : i++) {
          move disarmedOf.get(i) to event.actress;
          event.add(MEvent__new(event.actress, DA_Manipulate, DV_TAKE,
                                disarmedOf.get(i), DCharacter__PC, event.loc));
        }

        event.secondObj = self.getRescuer(DCharacter__PC, witnesses);
        if (event.secondObj || event.loc ofclass DGondolaLocation) {
          !"rescuer" or gondola NPC will drag you to obs_deck
          wakeIn = Observation_Deck;
          event.detail = -1;
        }else {
          !will be left behind
          wakeIn = event.loc;
          event.detail = -2;
        }
      }

      !remove any revenant (whether fell to NPC or revenant)
      remove revenant;

      !Fast-forward any go_party
      if (MTriggerManager.hasState(DST_GoParty) &&
           DNPC__SelectActive(DST_GoParty.detail)) {
        !still someone active to lead GoParty
        !PC just dropped
        if (DST_GoParty.detail.contains(DCharacter__PC)){
          event.add(MEvent__new(nothing, DA_ChangeState, nothing,
                      DST_GoParty, DV_DROP, event.loc, DCharacter__PC));
          DST_GoParty.detail.remove(DST_GoParty.detail.indexOf(DCharacter__PC));
        }
        !make sure we can get in (no betrayal possible w/ unconscious PC)
        give hatch_to_Gondola ~locked;
        sub = MEvent__new(nothing, GoParty_Offscreen, nothing,
                          nothing, nothing, event.loc);
        GoParty_Offscreen.reacts = nothing;
        GoParty_Offscreen.play(sub, true);
        event.add(sub);
      }

      !heal/revive and advance time
      print "Then everything goes black.^";
      new_line;
      new_line;
      DCharacter__PC.damage(-1);  !prints waking message
      DemeterTime++;
      if (DemeterTime > 2) {
        DemeterTime = -1;
      }

      !In the meantime, regardless of where PC is going to wake up,
      ! move any NPCs in from deck
      if (door_to_Observation_Deck hasnt locked ||
          DNPC__GetActiveNPCs(DGondolaLocation, true)) {
        !can get in, or someone to let them in
        deckers = MDramaManager.getPresent(true, Observation_Deck);
        for (i = 0 : i < deckers.size() : i++) {
          !Even if no one around to help, uncons. NPC wake long enough to
          ! drag themselves in
          move deckers.get(i) to deckers.get(i).getPassengerRoom();
        }
        MList.destroy(deckers);
      }

      !now, finally narrate waking
      PlayerTo(wakeIn);  !will produce a look at new location

      if (wakeIn == Observation_Deck) {
        !regardless of whether dragged, left after NPC attack, or fell to rev:
        give door_to_Observation_Deck ~open;
        if (door_to_Observation_Deck has lockable) {
          give door_to_Observation_Deck locked;
        }

        if (event.loc ~= Observation_Deck) {
          !was dragged here
          new_line;
          print "Aside from your other injuries, your clothes are rumpled
            and pulled askew, your wrists are bruised, and your shoulders
            are sore. In short, it feels like you were dragged out here,
            though not very gently.^";
        }
        if (disarmedOf.size()) {
          if (event.loc ~= Observation_Deck) {
            new_line;
            print "It also ";
          }else {
            new_line;
            print "It ";
          }
          print "seems that someone has relieved you of ";
          if (disarmedOf.size() > 1) {
            print "all your potential weapons.^";
          }else {
            print "your ", (name) disarmedOf.get(0), ".^";
          }
        }
      }

      new_line;
      print "You are not sure how much time passed while you were unconscious";
      if (~~(wakeIn == Ladderway || wakeIn == WC ||
             wakeIn ofclass DZeppelinLocation)) {
        print ", but a glance at the sky ";
        if (wakeIn == Observation_Deck) {
          print "all around you";
        }else {
          print "through the window here";
        }
        print " shows that it is now ";
        switch (DemeterTime) {
          0: print "night";
          1: print "dawn";
          2: print "late morning";
          -1: print "sunset";
        }
      }
      print ".^";

      if (wakeIn == YourBottomBunk) {
        event.add(MEvent__new(DCharacter__PC, DA_Travel, DV_GO, Your_Room,
                                event.secondObj, event.loc));
        move event.secondObj to Your_Room;
        new_line;
        print (name) event.secondObj, " leans over you.^";
        event.secondObj.speakTo(DCharacter__PC);
        print "You're awake! I was worried there for a while...~^";

        !a brief manual report (too hard to use GoParty_Reports properly here,
        ! since the GoParty fast forward happens within this scene).
        event.secondObj.speakTo(DCharacter__PC);
        print "After you fell, that thing also attacked ";
        npc = event.get(0).dirObj;
        if (npc == event.secondObj) {
          print "me";
        }else {
          event.secondObj.printAddressFor(npc);
        }
        print " while I tried to drag you clear.";
        if (npc == event.secondObj) {
          print "~^";
          print (name) npc, " shows you ", (my) npc, " wounds.^";
          npc.speakTo(DCharacter__PC);
          print "Then, I don't know why, but it suddenly turned
            and took off! We were both lucky, I guess.~^";
        }else {
          print " I yelled, and for some reason, that suddenly scared
            the thing off. ";
          if (npc.health <= 0) {
            print "But... it wasn't enough to save ", (name) npc, "! ";
            if (npc.health == 0) {
              !expired
              npc.damage(1, true);
              event.get(0).verb = DV_KILL;
            }
            print (CI) npc, "'s dead!~^";
          }else {
            event.secondObj.printAddressFor(npc);
            print " was injured, but ", (I) npc, " is still alive.~^";
          }
        }
      }
      !Otherwise, will wake where fell, which is pretty self explanatory

      MList.destroy(witnesses);
      if (disarmedOf) {
        MList.destroy(disarmedOf);
      }
    ],
;