docs: def character_copy(self, char):
          """Return a dictionary describing character ``char``."""
          ret = self.character_stat_copy(char)
          chara = self._real.character[char]
          nv = self.character_nodes_stat_copy(char)
          if nv:
              ret['node_val'] = nv
          ev = self.character_portals_stat_copy(char)
          if ev:
              ret['edge_val'] = ev
          avs = self.character_avatars_copy(char)
          if avs:
              ret['avatars'] = avs
          rbs = self.character_rulebooks_copy(char)
          if rbs:
              ret['rulebooks'] = rbs
          nrbs = self.character_nodes_rulebooks_copy(char)
          if nrbs:
              for node, rb in nrbs.items():
                  assert node in chara.node
                  if 'node_val' not in ret:
                      ret['node_val'] = {}
                  nv = ret['node_val']
                  if node not in nv:
                      nv[node] = {}
                  nv[node]['rulebook'] = rb
          porbs = self.character_portals_rulebooks_copy(char)
          if porbs:
              for orig, dests in porbs.items():
                  ports = chara.portal[orig]
                  for dest, rb in dests.items():
                      assert dest in ports
                      if 'edge_val' not in ret:
                          ret['edge_val'] = {}
                      ev = ret['edge_val']
                      if orig not in ev:
                          ev[orig] = {}
                      ov = ev[orig]
                      if dest not in ov:
                          ov[dest] = {}
                      ov[dest]['rulebook'] = rb
          return ret