Difference between revisions of "Tintin"

From Flexible Survival
Jump to: navigation, search
m
(Describe how to Install, Update, and Use Inutt's tested and updated TinTin++ within Tmux)
Line 1: Line 1:
For anyone who wishes to use TinTin++ here are a few handy Flexible Survival scripts and accompanying python scripts which you can use (or cut and paste out of) that I've written and refined over the past few years.
+
==Install==
  
The commands that follow should be copied into their own files in a folder of your choosing. My scripts are in a folder called tt in my home directory. I then use tmux to split my window into four sections:
+
===Required packages (for Debian Linux)===
Top left is input and everything coming from the mud.
 
Top right is all players, pets, enemies and enemy pet health (updated by parsing fprompt).
 
Bottom left is all chat-related stuff.
 
Bottom right is powers used (with damage), XP collected, tokens and salvage gathered, daily mission completion status and other misc battle-related stuff.
 
  
Here's what it looks like when it's running:<br>
+
Become root, either via '''sudo -i''' or some other method.
[[File:Screenshot_2015-08-13_13-00-12.png|900px]]
 
  
 +
Run all of these commands as '''root''' (yes, bash is probably pre-installed, this is just making sure).
  
I have a bash script (anwen_mud.sh) that starts tmux and configures the four sections:
+
apt-get update
<pre>
+
apt-get install tmux tintin++ bash git nano \
#!/bin/bash
+
libcommon-sense-perl \
cd ~/tt
+
libdatetime-perl \
 +
libdatetime-event-sunrise-perl \
 +
libfile-changenotify-perl \
 +
libfile-pid-perl \
 +
libjson-perl \
 +
libtest-lwp-useragent-perl \
 +
libpath-class-perl \
 +
libtime-duration-perl
  
tmux -2 new-session -d -s 'mud'
+
Type '''exit''' (or ctrl+d) to end the session if you opened a new root session for this.
  
tmux new-window -t 'mud':1 -n 'mud'
+
FIXME: Are Getopt::Long and Term::ANSIColor built in, there don't seem to be Debian packages.
tmux split-window -h -p 26
 
tmux select-pane -t 0
 
tmux send-keys "tt++ anwen_start" C-m
 
tmux select-pane -t 1
 
tmux send-keys "tail -f anwen_hp 2>/dev/null" C-m
 
tmux select-pane -t 0
 
tmux split-window -v
 
tmux send-keys "tail -f anwen_chatlog" C-m
 
tmux select-pane -t 2
 
tmux split-window -v
 
tmux send-keys "tail -f anwen_stats" C-m
 
tmux select-pane -t 0
 
tmux -2 attach-session -t 'mud'
 
</pre>
 
  
 +
===Download the script package===
  
Generic connection script, note that this is linux based so the log file location needs to be changed if you're using WinTin in linux I save it with the name 'charname_start':
+
Next, run these commands as your normal user account (not root).  Replace any bold names with file-paths of your choosing.  Also remember that once a path exists, tab-complete often works for typing it out.
<pre>
 
#nop {==================================================================}
 
#nop {Python stuff}
 
#nop {==================================================================}
 
#run py python
 
#py import fs_python as fs
 
  
#py fs.config.player = "CHARNAME"
+
cd '''AnywhereYouWant'''
#py print(fs.config.player)
+
git clone https://gitlab.com/inutt/flexible-survival-ui.git '''fs-ui'''
#py fs.read_vars()
+
chmod +x '''fs-ui'''/flexible_survival
#py import time
+
'''fs-ui'''/flexible_survival
  
#action {tintin (%1) %2} {#%1 %2}
+
===Very minimal config.json===
  
#nop {==================================================================}
+
nano '''fs-ui'''/config.json
#nop {End of python stuff}
 
#nop {==================================================================}
 
  
#alias {start_fs} {#session fs flexiblesurvival.com 2000}
+
Above nano is used to edit the config file, if you prefer a different editor use that.  The launcher script should have setup the config file to be readable only by admins (root) and your exact user account.
start_fs
 
  
#split
+
* '''"character": "",''' and
 +
* '''"password": "",''' MUST be filled out.
  
#act {Welcome to Flexible Survival:}
+
JSON ignores non-printing 'whitespace' and requires that a key/value sets (contained in { } and called an object) have values in the middle separated by commas, but NO comma at the end.  {"character": "USER", "password": "PASSWORD"}.  Any values you don't want to change can be deleted.  Thus this might be an example minimal configuration file:
{
 
    #unticker {reconnect};
 
    #send connect CHARNAME YOUR PASSWORD;
 
    #var connected 1;
 
    #read anwen_scripts
 
}
 
</pre>
 
  
Next are those functions and values unique to my characters that override those in the scripts_all file that follows this one.
+
{
<pre>
+
    "fs": {
#var playername Anwen
+
        "character": "YOURUSER",
#highlight {Anwen} {light magenta}
+
        "password": "YOURPASS"
#highlight {anwen} {light magenta}
+
    }
 +
}
  
#var hp_log anwen_hp
+
In the above the extra commas after the password line, and that closing } after the "fs" key have been removed.  Again, the whitespace doesn't matter, so it could also be just (with no spaces even).
#var stats_log anwen_stats
 
#var chat_log anwen_chatlog
 
  
#nop {==================================================================}
+
{"fs":{"character":"YOURUSER","password":"YOURPASS"}}
#nop {Here we setup default variable values}
 
#nop {==================================================================}
 
#var messages 1
 
#var boton 0
 
#var bat 0
 
#var continue 0
 
#var ambushed 0
 
#var party_invite_status 1
 
#var party_invite_status_text Trusted
 
#var hptop 90
 
#var entop 90
 
#var submit 15
 
#var beeps 0
 
#var daily_status 0
 
#var current_location None
 
#var fallen 0
 
#var targeting 0
 
#var target_mode 0
 
#var enemy_list None
 
#var player_list None
 
#var down None
 
#var once_command nop
 
#var bound 0
 
#var load 0
 
#var completion
 
#var reward_lvl
 
#var alu_ic 0
 
  
 +
===Setting where the window splits to panes===
  
#alias {^dailys %5} {
+
The numbers in the '''tmux''' section are how you configure the split of the window.  You'll probably want to keep them and change them to suit your own needs.
    #send ooc Anwen !daily %5;
 
    #send ooc Hope !daily %5;
 
    #send ooc Aluthal !mission %5;
 
    #send ooc Skade !daily %5
 
}
 
  
#alias {^pets} {use bump;use grind;use Totemic deer}
+
    14 chat
#alias {^buff} {#send ooc Aluthal !buff}
+
  ------+-----------
 +
  status|
 +
  ------|  main
 +
  map 27|
 +
  64=>  |
 +
    "chat_height": 14,
 +
    "map_width": 64,
 +
    "map_height": 27,
 +
    "status_height": 16
  
#nop Read in scripts_all first then overwrite standard functions with those that follow.
+
Note: '''status_height''' doesn't actually set the height.  It tells the status update script how tall this section is so that it ''might'' omit some spacing or features to fit.
#read scripts_all
 
  
#nop CUSTOM STUFF FOLLOWS
+
===Final config.json===
#nop {==================================================================}
 
#nop {Redirects to chat_log}
 
#nop {==================================================================}
 
#act {^[{The Red Court|the red court}] %5$} {
 
    #line log {$chat_log}
 
} {2}
 
  
#nop {==================================================================}
+
You probably also want to set "data_dir": "SOMETHING", which is where your map data and log files will be stored.  This won't be created for you, so make sure you create it first. E.G.
#nop {sexytimes triggers}
 
#nop {==================================================================}
 
  
#nop {==================================================================}
+
mkdir "~/Documents/Flexible Survival Logs"
#nop {misc game and partying triggers}
 
#nop {==================================================================}
 
  
#nop {==================================================================}
+
Then your config.json file might look something like this
#nop {battle and ooc game triggers}
+
nano '''fs-ui'''/config.json
#nop {==================================================================}
 
  
#nop {==================================================================}
+
{
#nop {fighty time triggers}
+
    "tmux": {
#nop {==================================================================}
+
        "session_name": "Flexible Survival",
 +
        "chat_height": 14,
 +
        "map_width": 64,
 +
        "map_height": 27,
 +
        "status_height": 16
 +
    },
 +
    "fs": {
 +
        "character": "YOURUSER",
 +
        "password": "YOURPASS",
 +
        "data_dir": "~/Documents/Flexible Survival Logs"
 +
    }
 +
}
  
#act {^Aluthal goes [IC] In-Character.} {#var alu_ic 1}
+
If you're using WSL this gets more complicated.  "/mnt/c/Users/WindowsAccountName/My Documents/Flexible Survival Logs" might work for most.  If it doesn't, talk to whomever maintains the PC.  Tab-completion is really helpful here... mkdir /mnt/c/User (TAB) and then hit tab a couple more times to get a good guess at user account and My Documents locations to start in.
  
#act {^<Random Encounter> $playername is ambushed!} {
+
With that setup you SHOULD be able to (after setup!)
    #showme AMBUSHED;
 
    #var ambushed 1;
 
    #showme BATTLE STARTED;
 
    #var bat 1;
 
    #var alu_ic 0;
 
    #delay {ambushed} {#var ambushed 0} {60};
 
    #py fs.battle_timer("started")
 
}
 
  
#act {^<%6/%7 hp %10 /%11 m 0 /0 mv} {
+
===Get updates===
    #var hpnow %6; #var hpmax %7;
 
    #var ennow %10; #var enmax %11;
 
    #math {hpper} {($hpnow/$hpmax) * 100.00};
 
    #math {enper} {($ennow/$enmax) * 100.00};
 
    #if {$boton == 1} {
 
        #if {$bat == 0} {
 
            #nop {#showme {NOT IN BATTLE}};
 
            #if {$hpper >= $hptop && $enper >= $entop && $ambushed == 0 && $alu_ic == 1} {
 
                #undelay {search_time};
 
                #delay {search_time} {#send search} {10}
 
            };
 
            #else {
 
                #undelay {waiting};
 
                #delay {waiting} {#send mprompt} {10}
 
            };
 
        };
 
        #else {
 
            #if {$hpper <= $submit} {
 
                #var alu_ic 1;
 
                #send submit $targeting
 
            };
 
        };
 
    };
 
    #format hitpoints {%cHP %d/%d%c} {light green} {$hpnow} {$hpmax} {white};
 
    #format energypoints {%cEN %d/%d%c} {light blue} {$ennow} {$enmax} {white};
 
    #if {$hpper < 100 || $enper < 100} {
 
        #showme STATUS: $hitpoints $energypoints $hpper $enper
 
    };
 
    time
 
}
 
  
#nop {==================================================================}
+
cd '''fs-ui'''
#nop {Dump battle damage to stats_log.}
+
git pull
#nop {==================================================================}
+
 +
This can be run any time (in where-ever you had the download stored).  If there are any updates or bugfixes; though you might need to update your config.json file to use new features.
  
#nop {==================================================================}
+
==Connect==
#nop {grab player stats from fprompt for logging.}
 
#nop {==================================================================}
 
  
#nop {==================================================================}
+
* '''fs-ui'''/flexible_survival
#nop {Auto targeting}
 
#nop {==================================================================}
 
  
#nop {==================================================================}
+
When running '''Ctrl+B (arrow key)''' (hold down control, tap b, release both; then press an arrow key) can be used to move the input-focus between panes (text areas within that window).  '''Up''' and '''Down''' arrow keys are the ones you'll care about.  Up to go to the chat channels, down to go back to muck input.  You type all commands in the main muck window, even though the text shows up above.
#nop {Status stuff}
 
#nop {==================================================================}
 
  
</pre>
+
==Windows 10 WSL==
  
Last is a series of aliases, actions and other functions that are common to all of my characters:
+
If you'd like to use TinTin++ on Windows, installing a [https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux WSL] based distribution such as Debian is highly recommended.  If you have experience with a different distribution maintaining a server, including getting perl5 dependencies installed based on error messages, then go ahead and go with that. Debian has been selected here for being focused on Freedom, Liberty, and Stability, as well as generally providing clear directions for upgrades.
<pre>
 
#config {packet patch} {0.5};    #nop {Fixes rendering issues}
 
#message variable off
 
  
#gag nop
+
Note: Windows 10 S tries to be a "safe" OS that [https://devblogs.microsoft.com/commandline/will-linux-distros-run-on-windows-10-s/ restricts user freedom, and thus won't run even WSL].  They also offer an upgrade, for a fee, to normal-freedom Windows 10 (no S).
#TICKER {keepalive} {#send nop; time; #send mprompt} {60}
 
  
#send {pose #prepend <ic>}
+
Please follow Debian's [https://wiki.debian.org/InstallingDebianOn/Microsoft/Windows/SubsystemForLinux official guide] for installing on WSL.  It will likely have links updated as versions of things change.
#send {spoof #show}
 
#send {tick on}
 
#send {botmode off}
 
#format {bot_status} {%cBOT%c} {light green} {white}
 
  
#alias {^fp} {#send look}
+
==History==
#alias {^moff} {#var messages 0}
 
#alias {^mon} {#var messages 1}
 
#alias {^once %5} {#var once_command %5}
 
#alias {^gt %1} {#showme gothere %1}
 
#alias {^back} {#var bound 1; #py fs.edit_descrip("home")}
 
#alias {^tied} {#var bound 1; #py fs.edit_descrip("tied")}
 
#alias {^away} {#var bound 0; #py fs.edit_descrip("away")}
 
#alias {^fucked} {#py fs.secret($playername, "all")}
 
#alias {^add %5} {#py fs.party_list("add", "%5")}
 
#alias {^del %5} {#py fs.party_list("del", "%5")}
 
#alias {^party_check} {#py fs.party_list("check", "None")}
 
#alias {^daily?} {#py fs.daily_timer(); #var completion {}; #var reward_lvl {}}
 
#alias {^stat on} {#ticker {stats} {#send mprompt} {10}}
 
#alias {^stat off} {#unticker {stats}}
 
#alias {^pyes} {#var party_invite_status 2; #var party_invite_status_text Open}
 
#alias {^pno} {#var party_invite_status 0; #var party_invite_status_text Closed}
 
#alias {^ptrust} {#var party_invite_status 1; ; #var party_invite_status_text Trusted}
 
#alias {^beeps} {#var beeps 1}
 
#alias {^quiet} {#var beeps 0}
 
#alias {^pmentor %5} {partymentor %5}
 
#alias {^diff %5} {#send web #difficultyLevel %5}
 
#alias {^pher %5} {#send web #difficultyQuantity %5}
 
#alias {^danger} {ooc $playername !danger}
 
#alias {^up} {#var fallen 0;#var down None}
 
#alias {^boton} {#send ooc $playername !bot on}
 
#alias {^botoff} {
 
    #if {$bat == 1} {
 
        #send once ooc $playername !bot off
 
    };
 
    #else {
 
        once ooc $playername !bot off
 
    }
 
}
 
#alias {^botoff} {
 
    #if {$bat == 1} {
 
        once ooc $playername !bot off
 
    };
 
    #else {
 
        #send ooc $playername !bot off
 
    }
 
}
 
#alias {time}
 
{
 
    #format clock {%c%t} {light green} {%T};
 
    #showme {$clock}
 
}
 
  
#nop {==================================================================}
+
[[https://en.wikipedia.org/wiki/TinTin%2B%2B TinTin++]] is the result of almost 30 years of development by a series of programmers. While an absolute dinosaur of a computer from the era of it's origin in the mid 1990s probably couldn't run it today, just about anything from the last 20 years probably can.
#nop {Redirects to chat_log}
 
#nop {==================================================================}
 
#act {^[{Auction|Bile|Bitch|Lfg|Links|Naughty|Newbie|Pickup|Public|Rp|Science|Tg|Update}] %5$} {
 
    #line log {$chat_log}
 
} {2}
 
#act {^<Give> %4 gives %5 to you.} {
 
    #format {give} {%c%t %c<%cGIFT%c> %c%s gave %s.} {white} {%T} {yellow} {cyan} {yellow} {white} {%4} {%5};
 
    #line log {$chat_log} {$give}
 
} {6}
 
#nop {#act {^[%2$} {#line log {$chat_log}} {2} }
 
  
#act {^<ic> %2$} {#format {ic} {%c%t %c<%cIC%c> %c%s} {white} {%T} {yellow} {cyan} {yellow} {white} {%2}; #line log {$chat_log} {$ic}}
+
Several older versions of this wiki page exist (updated during 2013 and 2015) with the final version of that series updated on [https://wiki.flexiblesurvival.com/index.php?title=Tintin&oldid=310992 2015-08-25T14:09:09] you might find Anden's examples useful if interested in battle tactics, though they're written assuming python2 (which is no longer supported); while Inutt's code repository uses some perl5 helpers that could be replaced or omitted entirely without breaking the basic multipane functionality. (They help produce the formatted status window and optionally near realtime weather.)
#act {^<OOC> %2$} {#format {ooc} {%c%t %c<%cOOC%c> %c%s} {light green} {%T} {yellow} {cyan} {yellow} {white} {%2}; #line log {$chat_log} {$ooc}}
 
#act {^[%5(#%6)]: %2$} {#format {spoof} {%c%t %c<%cSP%c> %c%s} {white} {%T} {yellow} {cyan} {yellow} {white} {%2}; #line log {$chat_log} {$spoof}}
 
  
#act {^You %, %2$} {#format {say} {%c%t %c<%cYS%c> %c%s} {light green} {%T} {yellow} {cyan} {yellow} {white} {%2}; #line log {$chat_log} {$say}} {6}
+
Inutt, one of the coding wizards for FS, has a nice setup for TinTin that's published on their [https://gitlab.com/inutt/flexible-survival-ui GitLab] pageKetsueki made some small contributions (currently a pull request) to make it more suitable for users with different terminal sizes. Though it does expect a computer screen capable of displaying at least 120 columns of characters across (in that case a split of about 29 for the map and status area, and thus 90 or so for the main text area is recommended). If you're on a 1080p+ monitor, using a normal Graphical User Interface (E.G. Windows, OS X, anything else that runs a web browser) and using a full-screen "terminal" program of any sort (find one you like for your OS) you probably do have that many columns.
#act {^You page, %2$} {#format {yp} {%c%t %c<<%cYP%c>> %c%s} {light green} {%T} {yellow} {cyan} {yellow} {white} {%2}; #line log {$chat_log} {$yp}} {5}
 
#act {^In a page-pose to $playername, %2$} {#format {pp} {%c%t %cIn a page-pose to you,%c %c%s} {light green} {%T} {yellow} {cyan} {white} {%2}; #line log {$chat_log} {$pp}}
 
#act {^%4 gives %5 to $playername.} {
 
    #format {give} {%c%t %c<%cGIFT%c> %c%s %s} {light green} {%T} {yellow} {cyan} {yellow} {white} {%4} {%5};
 
    #line log {$chat_log} {$give}
 
}
 
#act {^In a page-pose to you, %5 %6} {
 
    #format {ppose} {%c%t %cP-P %c%s} {light green} {%T} {cyan} {white} {%0};
 
    #nop {#format {ppose} {%c%t %cP-P %c%s %c%s} {light green} {%T} {cyan} {yellow} {%5} {white} {%6} };
 
    #showme {\a\};
 
    #line log {$chat_log} {$ppose}
 
}
 
#act {^In a page-pose to you and %5, %6 %7} {
 
    #format {ppose} {%c%t %cP-P %c%s} {light green} {%T} {cyan} {white} {%0};
 
    #nop {#format {ppose} {%c%t %cP-P %c(%s) - %c%s %c%s} {light green} {%T} {cyan} {yellow} {%5} {light blue} {%6} {white} {%7} };
 
    #showme {\a\};
 
    #line log {$chat_log} {$ppose}
 
}
 
#act {^In a page-pose to %5 and you, %6 %7} {
 
    #format {ppose} {%c%t %cP-P %c%s} {light green} {%T} {cyan} {white} {%0};
 
    #showme {\a\};
 
    #line log {$chat_log} {$ppose}
 
}
 
#act {^%5 pages, %2 to you.} {
 
    #nop {#py fs.battle_trigger("%5", %2);};
 
    #format {page} {%c%t %c%5 %cpages,%c %c%s} {white} {%T} {yellow} {cyan} {yellow} {white} {%2};
 
    #showme {\a\};
 
    #line log {$chat_log} {$page}
 
}
 
#act {%5 pages, "%6" to you and %7.} {
 
    #format {page} {%c%t %c%s %cpages, %c"%s" to you and %s} {white} {%T} {yellow} {%5} {cyan} {white} {%6} {%7};
 
    #showme {\a\};
 
    #line log {$chat_log} {$page}
 
}
 
 
 
#nop {==================================================================}
 
#nop {sexytimes triggers}
 
#nop {==================================================================}
 
#act {^<Fuck> %5 wants to fuck you. Type fuck %5 to agree.} {
 
    #var sexy %5;
 
    #py fs.taken("$sexy", "pussy")
 
}
 
#act {<Fuck> %5 wants oral sex with you. Type fuck %5 mouth to agree.} {
 
    #var sexy %5;
 
    #py fs.taken("$sexy", "mouth")
 
}
 
#act {<Fuck> %5 wants an ass fuck with you. Type fuck %5 ass to agree.} {
 
    #var sexy %5;
 
    #py fs.taken("$sexy", "ass")
 
}
 
#act {^<OOC> %5 says, "!check"} {#py fs.secret("%5", "%5")}
 
 
 
#act {^<Submit> $playername submits to %5} {
 
    #py fs.fucked()
 
}
 
 
 
#nop {==================================================================}
 
#nop {misc game and partying triggers}
 
#nop {==================================================================}
 
#act {Type +reward now!} {+reward}
 
#act {(You sense a new message at OOC - %1 by Avatar: +REWARD)} {+reward}
 
#act {You receive a new mission. Clear out opposition at %5!} {#send ooc My daily is: %5; #var daily_status 1}
 
#act {^gothere %30} {#var place %30; #py fs.gothere("$place")}
 
#act {You have been invited to join %5's party. Type pjoin %5 to accept and meet them.} {#send pjoin %5}
 
#act {%5 (Level %6) wishes to join your party. Type pinvite %5 to accept.} {#py fs.party_invite("%5", int("$party_invite_status"))}
 
 
 
#nop {==================================================================}
 
#nop {battle and ooc game triggers}
 
#nop {==================================================================}
 
#act {<OOC> %5 says, "!target %4"} {#send ooc Targeting %4; #send target %4}
 
#act {<OOC> %5 says, "$playername !%.aily %5"}{#send daily %5}
 
#act {<OOC> %5 says, "$playername !pinvite %6"} {#send pinvite %6}
 
#act {<OOC> %5 says, "$playername !go %4"} {#var loc %4; #py fs.gothere("$loc")}
 
#act {<OOC> %5 says, "$playername !auto"} {#send ooc Auto on.; #send auto on}
 
#act {<OOC> %5 says, "$playername !search"} {#send search}
 
#act {<OOC> %5 says, "$playername !bot on"} {#send botmode on}
 
#act {<OOC> %5 says, "$playername !bot off"} {
 
    #var boton 0;
 
    #if {$bat == 1} {
 
        once botmode off;
 
        #send AUTO: Understood. Botmode will be switched off when the current battle is completed.
 
    };
 
    #else {
 
        botmode off
 
    }
 
}
 
#act {<OOC> %5 says, "$playername !danger"} {#send +haz; #send ooc Danger: $danger Pheromone: $pheromone}
 
#act {<OOC> %5 says, "$playername !leave"} {#send pleave}
 
#act {<OOC> %5 says, "$playername !home"} {#send home}
 
#act {<OOC> %5 says, "$playername !help"} {
 
    #send @paste %5;
 
    #send For an automatic pinvite use ooc $playername !pinvite;
 
    #send To get me to leave the party use ooc $playername !leave;
 
    #send To get me to go home use ooc $playername !home;
 
    #send To get me to target an enemy use ooc !target X;
 
    #send To get me to switch auto combat on use ooc $playername !auto;
 
    #send To get me to search use ooc $playername !search;
 
    #send To get me to go somewhere use ooc $playername !go DIR where DIR is one of: [n,e,s,w,ne,nw,se,sw,u,d];
 
    #send Switch on botmode with ooc $playername !bot on;
 
    #send Switch off botmode with ooc $playername !bot off;
 
    #send You can verify my currently set danger levels with ooc $playername !danger;
 
    #send Refresh my daily with ooc !daily [daily location] at the correct location;
 
    #send .
 
}
 
 
 
 
 
#nop {==================================================================}
 
#nop {fighty time triggers}
 
#nop {==================================================================}
 
#act {DN%5 PH%6 %7} {#var danger %5; #var pheromone %6}
 
#act {^You have been defeated!} {
 
    #if {boton == 1} {
 
        #if {bat == 1} {
 
            once #send ooc $playername !bot off
 
        };
 
        #else {
 
            #send ooc $playername !bot off
 
        }
 
    }
 
    #var boton 0;
 
    #var bat 0;
 
    #showme {\a\}
 
}
 
#act {^<Botmode> Your bot mode is now enabled} {
 
    #format {bot_status} {%cBOT%c} {light red} {white};
 
    #var boton 1;
 
    #var bat 0;
 
    #send search
 
}
 
#act {^<Botmode> Your bot mode is now disabled} {
 
    #format {bot_status} {%cBOT%c} {light green} {white};
 
    #var boton 0;
 
    #var bat 0;
 
    #unticker searching
 
}
 
#act {^<Botmode> Botmode is currently on, type botmode off to disable it.} {
 
    #format {bot_status} {%cBOT%c} {light red} {white};
 
    #send +haz
 
}
 
#act {NO INFECTION DATA FOUND FOR THIS AREA.} {
 
    #showme {Safe Area, botmode being switched off};
 
    #if {$boton == 1} {
 
        #format {bot_status} {%cBOT%c} {light green} {white};
 
        #send {ooc $playername !bot off}
 
    }
 
}
 
#act {^<Search> $playername searches for trouble.} {#delay {search_notification} {#line log {$stats_log} {Time to search again!}} {60}}
 
#act {^<Random Encounter> $playername is ambushed!} {
 
    #showme AMBUSHED;
 
    #var ambushed 1;
 
    #showme BATTLE STARTED;
 
    #var bat 1;
 
    #delay {ambushed} {#var ambushed 0} {60};
 
    #py fs.battle_timer("started")
 
}
 
#act {^== ROUND %5 ==} {
 
    #var bat 1;
 
    #format {round} {%c== ROUND %5 ==} {white};
 
    #line log {$stats_log} {$round};
 
    #send look
 
}
 
#act {^</////// Battle %5! ///////>} {
 
    #var bat 0;
 
    #var ambushed 0;
 
    #py fs.config.feral_list = {};
 
    #send goic;
 
    #send $once_command; #var once_command nop;
 
    #py fs.config.feral_list = {};
 
    #if {$daily_status == 1} {#send {quest}};
 
    #line log {$stats_log} {Battle %5!};
 
    #py fs.battle_timer("finished");
 
    #send fprompt;
 
    #send mprompt
 
}
 
#act {^<%6/%7 hp %10 /%11 m 0 /0 mv} {
 
    #var hpnow %6; #var hpmax %7;
 
    #var ennow %10; #var enmax %11;
 
    #math {hpper} {($hpnow/$hpmax) * 100.00};
 
    #math {enper} {($ennow/$enmax) * 100.00};
 
    #if {$boton == 1} {
 
        #if {$bat == 0} {
 
            #nop {#showme {NOT IN BATTLE}};
 
            #if {$hpper >= $hptop && $enper >= $entop && $ambushed == 0} {
 
                #undelay {search_time};
 
                #delay {search_time} {#send search} {10}
 
            };
 
            #else {
 
                #undelay {waiting};
 
                #delay {waiting} {#send mprompt} {10}
 
            };
 
        };
 
        #else {
 
            #if {$hpper <= $submit} {
 
                #send submit $targeting
 
            };
 
        };
 
    };
 
    #format hitpoints {%cHP %d/%d%c} {light green} {$hpnow} {$hpmax} {white};
 
    #format energypoints {%cEN %d/%d%c} {light blue} {$ennow} {$enmax} {white};
 
    #if {$hpper < $MAX || $enper < $MAX} {
 
        #showme STATUS: $hitpoints $energypoints $hpper $enper
 
    };
 
    time
 
}
 
#act {^Health: %5 -> %6/%7} {
 
    #var hpnow %5; #var hpmax %6;
 
    #format hitpoints {%cHP %d/%d%c} {light green} {$hpnow} {$hpmax} {white};
 
    #send mprompt;
 
    #showme HEALTH
 
}
 
#act {^Energy: %5 -> %6/%7 --} {
 
    #var ennow %5; #var enmax %6;
 
    #format energypoints {%cEN %d/%d%c} {light blue} {$ennow} {$enmax} {white};
 
    #send mprompt;
 
    #showme ENERGY
 
}
 
#act {Players: %6} {
 
    #var player_list %6;
 
    #py fs.create_player_list("$player_list");
 
    #send fprompt;
 
    #send mprompt
 
}
 
#act {^Things: %6} {
 
    #var ferals %6;
 
    #py fs.create_feral_list("$ferals");
 
    #py fs.target_feral(int($target_mode))
 
}
 
#act {^<Summon> Pet: %5 appears at %6. %7 side.} {
 
    #showme PET SUMMONED, RETARGETING;
 
    #var targeting %6;
 
    #send Target $targeting;
 
    #py fs.config.current_target = int($targeting);
 
    #py fs.target_feral(int($target_mode))
 
}
 
#act {<Daily Mission> You make progress towards the daily mission(%5).} {
 
    #var completion %5;
 
    #if {$messages == 1} {
 
        #send ooc Mission completion: $completion;
 
        #send quest
 
    };
 
    #if {$beeps == 1} {
 
        #showme {\a\}
 
    }
 
}
 
#act {^Your daily mission is in %5: [    %6  ]} {
 
    #var reward_lvl %6;
 
    #line log {$stats_log} {Reward lvl: $reward_lvl};
 
    #if {$daily_reward == "400%"} {
 
        #send ooc AUTO: 400% reached! Activate speeeeeedmode!;
 
        #var daily_status 0
 
    }
 
}
 
#act {<Daily Mission> You have earned a difficulty ratio of %5, this earns you %6 reward tokens!} {
 
    #line log {$stats_log} {Got %6 tokens from daily mission!};
 
    #var completion;
 
    #var reward_lvl
 
}
 
#act {<Daily Mission> You have completed the mission!} {
 
    #delay {daily_refresh} {#send ooc AUTO: Time to get a new daily!} {64800};
 
    #var daily_status 0;
 
    #var daily_complete $clock;
 
    #py fs.daily_done()
 
}
 
#act {XP Gained: %5  --  Freecred Gained: %6} {
 
    #format {win} {%cXP: %5 FC: %6} {yellow};
 
    #line log {$stats_log} {$win}
 
}
 
#act {^Somewhere on the muck, %5 has disconnected.} {#nop} {5}
 
#act {^%5 has disconnected.} {
 
    #var boton 0;
 
    #format {disconnected} {%c%t %c%5 disconnected!%c} {light green} {$clock} {light red} {white};
 
    #line log {$chat_log} {$disconnected};
 
    #if {$bat == 1 && $boton == 1} {
 
        once botmode off;
 
        #send {ooc AUTO: %5 has dropped, botmode will be automatically switched off at the end of the battle.}
 
    }
 
} {6}
 
#act {^<Salvage> $playername manages to salvage %5 %6 salvage!} {
 
    #format {sal} {%cSalvage: %5 %6} {red};
 
    #line log {$stats_log} {$sal}
 
}
 
#act {^What a find! $playername's keen grasp of the scholarly leads them to find a %5! It's worth %6 Freecreds!} {#line log {$stats_log} {Item: %6FC}}
 
 
 
#nop {==================================================================}
 
#nop {Dump battle damage to stats log.}
 
#nop {==================================================================}
 
 
 
#act {^<[%5%]$playername><%6> %7 is cured of %8!} {#format {effect} {%c%6 %c%8%c} {magenta} {green} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> %7 affects $playername!} {#format {effect} {%c%6%c} {magenta} {green} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> %7. %8 takes %9 damage!} {#format {effect} {%c%6 %c%9%c} {magenta} {red} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> %7. %8 takes %9 damage! (%10)} {#format {effect} {%c%6 %c%9%c} {magenta} {red} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> %8 takes %9 damage! (%10)} {#format {effect} {%c%6 %c%9%c} {magenta} {red} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> Pet: %7 %8(%9) takes %10 damage!} {#format {effect} {%c%6 %c%10%c} {magenta} {red} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%4]%5($playername)><%6> %7. %8 takes %9 damage!} {#format {effect} {%c%5 %c%6 %c%9%c} {magenta} {green} {red} {white}; #line log {$stats_log} {$effect}}
 
#act {^<%5($playername)><%6> %7 is healed for %8 damage!} {#format {effect} {%c%5 %c%6 %8%c} {magenta} {green} {white}; #line log {$stats_log} {$effect}}
 
#act {^<$playername><%5> %6 is healed for %7 damage!} {#format {effect} {%c%5 %c%7 %c} {magenta} {light green} {white}; #line log {$stats_log} {$effect}}
 
#act {^<[%5%]$playername><%6> $playername is led astray by %8. %9 and loses momentum.} {#nop}
 
#act {^<Vampiric> $playername draws %5 points of regeneration.} #format {effect} {%cVampiric %c%5 %c} {magenta} {light green} {white}; #line log {$stats_log} {$effect}
 
 
 
#nop {==================================================================}
 
#nop {grab player stats from fprompt for logging.}
 
#nop {==================================================================}
 
 
 
#function {stats_formatting} {
 
    #nop {input vars: name;hp_now;hp_max;en_now;en_max;name_colour;list_name};
 
    #math {hp_per} {(%2/%3) * 100.00};
 
    #math {en_per} {(%4/%5) * 100.00};
 
    #var hp_col @colourise{$hp_per};
 
    #var en_col @colourise{$en_per};
 
    #format stats {%s%.22s %s%s/%s %s%s/%s} {%6} {%1} {$hp_col} {%2} {%3} {$en_col} {%4} {%5};
 
    #list {%7} {add} {$stats}
 
}
 
 
 
 
 
#function {colourise} {
 
    #if {%0 >= 100} {
 
        #nop {bold cyan};
 
        #return <168>
 
    };
 
    #elseif {%0 > 70} {
 
        #nop {bold blue};
 
        #return <148>
 
    };
 
    #elseif {%0 > 50} {
 
        #nop {bold green};
 
        #return <128>
 
    };
 
    #elseif {%0 > 30} {
 
        #nop {bright yellow};
 
        #return <138>
 
    };
 
    #elseif {%0 > 20} {
 
        #nop {bold white};
 
        #return <178>
 
    };
 
    #elseif {%0 > 10} {
 
        #nop {bright red};
 
        #return <118>
 
    };
 
    #else {
 
        #nop {blink red};
 
        #return <018>
 
    }
 
}
 
 
 
 
 
#nop {Feral pets}
 
#act {^Pet: %6%s<%7/%8 hp - %9/%10 en>} {
 
    #format feral_pet_name {Pet: %s} {%6};
 
    #var stats @stats_formatting{$feral_pet_name;%7;%8;%9;%10;<218>;fpet}
 
} {5}
 
#nop {Numbered Ferals}
 
#act {%5. %6%s<%7/%8 hp - %9/%10 en>} {
 
    #format feral_name {%s. %s} {%5} {%6};
 
    #var stats @stats_formatting{$feral_name;%7;%8;%9;%10;<118>;fer}
 
}
 
#nop {Player pets}
 
#act {%5(%6)%s<%7/%8 hp - %9/%10 en>} {
 
    #format pet_name {%s(%s)} {%5} {%6};
 
    #var stats @stats_formatting{$pet_name;%7;%8;%9;%10;<138>;pet}
 
} {6}
 
#nop {Primes - they don't have a number so add one.}
 
#act {Prime %6%s<%7/%8 hp - %9/%10 en>} {
 
    #var stats @stats_formatting{%6;%7;%8;%9;%10;<118>;fer}
 
} {5}
 
#nop {Players}
 
#act {%6%s<%7/%8 hp - %9/%10 en>} {
 
    #var stats @stats_formatting{%6;%7;%8;%9;%10;<128>;ply}
 
} {6}
 
#act {^<ENDLIST>} {
 
    #foreach {$fpet[%*]} {temp} {#list {stats_list} {add} {$temp}};
 
    #foreach {$fer[%*]} {temp} {#list {stats_list} {add} {$temp}};
 
    #foreach {$pet[%*]} {temp} {#list {stats_list} {add} {$temp}};
 
    #foreach {$ply[%*]} {temp} {#list {stats_list} {add} {$temp}};
 
 
 
    #list {fpet} {size} {fpet_list_size};
 
    #list {fer} {size} {fer_list_size};
 
    #list {pet} {size} {pet_list_size};
 
    #list {ply} {size} {ply_list_size};
 
    #format summary {<878>[P:%d p:%d F:%d f:%d] <168>0<148>98<128>76<138>54<178>3<118>2<018>1} {$ply_list_size} {$pet_list_size} {$fer_list_size} {$fpet_list_size};
 
    #list {stats_list} {add} {$summary};
 
   
 
    #math {line_buffer_size} {30 - $stats_list_size};
 
    #loop 1 $line_buffer_size blah {#list {stats_list} {insert} {1} { }};
 
    #foreach {$stats_list[%*]} {temp} {#line log {$hp_log} {$temp}};
 
    #list {fpet} {clear};
 
    #list {fer} {clear};
 
    #list {pet} {clear};
 
    #list {ply} {clear};
 
    #list {stats_list} {clear};
 
    #sys echo " " > '$hp_log'
 
}
 
 
 
#nop {==================================================================}
 
#nop {Auto targeting}
 
#nop {==================================================================}
 
#act {^<Power> %3. %4 is defeated by %5!} {
 
    #nop {FERAL};
 
    #var tgt_no %3; #var tgt_name %4;
 
    #format {pwr} {%c%3 %c(%5)%c} {red} {cyan} {white};
 
    #line log {$stats_log} {$pwr};
 
    #send look;
 
    #py fs.target_feral(int($target_mode))
 
} {5}
 
#act {^<Power> %4(%5) is defeated by %6!} {
 
    #nop {PET};
 
    #var tgt_name %4;
 
    #format {pwr} {%c%4 Pet down!} {cyan};
 
    #line log {$stats_log} {$pwr}
 
} {6}
 
#act {^<Power> Prime %4 is defeated by %5!} {
 
    #var tgt_name %4;
 
    #format {pwr} {%c%4 has fallen! (%5)} {light red};
 
    #line log {$stats_log} {$pwr};
 
    #py fs.player_down_check("$tgt_name")
 
}
 
#act {^<Power> %4 is defeated by %5!} {
 
    #nop {PLAYER};
 
    #var tgt_name %4;
 
    #format {pwr} {%c%4 has fallen!} {light red};
 
    #line log {$stats_log} {$pwr};
 
    #py fs.player_down_check("$tgt_name")
 
} {8}
 
 
 
#nop {==================================================================}
 
#nop {Status stuff}
 
#nop {==================================================================}
 
#act {--Contents of %6--} {
 
    #format current_location {%c%s} {white} {%6}
 
} {1}
 
 
 
#gag {^[Tick] %5}
 
#act {^[Tick] Avatar **Global Tick - %5 load**} {
 
    #format load {%cLD %s%c} {red} {%5} {white}
 
}
 
 
 
 
 
#function {bar_formatting} {
 
    #math {hp_per} {(%2/%3) * 100.00};
 
    #math {en_per} {(%4/%5) * 100.00};
 
    #var hp_col @colourise{$hp_per};
 
    #var en_col @colourise{$en_per};
 
    #format bar_stats {%c%s %s%s/%s %s%s/%s} {%6} {%1} {$hp_col} {%2} {%3} {$en_col} {%4} {%5};
 
    #return $bar_stats
 
}
 
 
 
#prompt {^<%6/%7 hp %10 /%11 m 0 /0 mv} {<100>@bar_formatting{$playername:;%6;%7;%10;%11;light magenta}<178> - $current_location - $load - $party_invite_status_text - $bot_status - $clock $completion $reward_lvl}
 
#send mprompt
 
#send +haz
 
daily?
 
</pre>
 
 
 
 
 
Main python script:<br>
 
<pre>
 
#! /usr/bin/env python
 
 
 
# Remember to double braces - they're used in string comprehension!
 
import datetime
 
import cPickle as pickle
 
import random
 
import re
 
import time
 
 
 
import config
 
 
 
 
 
ses = "fs"
 
config.time_check = time.clock()
 
 
 
 
 
def read_vars():
 
    filename = "/home/anwen/tt/fs_vars_{plyr}".format(plyr=config.player.lower())
 
    #print(filename)
 
    f = open(filename, "rb")
 
    config.party_list, config.next_daily = pickle.load(f)
 
    f.close()
 
 
 
 
 
# write variables to a pickle
 
def write_vars():
 
    filename = "/home/anwen/tt/fs_vars_{0}".format(config.player.lower())
 
    try:
 
        f = open(filename, "wb")
 
        pickle.dump([config.party_list, config.next_daily], f)
 
        f.close()
 
        #print("Data successfully written.")
 
    except:
 
        #print("Some data not found.")
 
        f = open(filename, "wb")
 
        config.party_list = []
 
        config.last_daily = 0
 
        pickle.dump([config.party_list, config.next_daily], f)
 
        f.close()
 
       
 
 
 
# =============================================================================
 
# Battle related functions
 
# =============================================================================
 
def create_feral_list(ferals):
 
    '''Compile a dict of ferals based on the contents of the "Things" list.
 
    Format is {feral_number: feral_name}
 
    '''
 
    config.feral_list = {}
 
    temp_list = ferals.split(",")
 
    for item in temp_list:
 
        item = item.strip()
 
        if "Pet:" in item:
 
            # Ignore player pets, NPCs or enemy pets.
 
            if config.debug: print("pet: {0}".format(item))
 
            continue
 
        elif "(!)" in item:
 
            # Game NPC's and items
 
            if config.debug: print("player pet: {0}".format(item))
 
            continue
 
        elif ". " in item:
 
            # It's a feral, add it to the dict.
 
            if config.debug: print("Feral! {0}".format(item))
 
            ind, name = item.split(". ")  # format is 1. name
 
            config.feral_list[int(ind)] = name
 
        elif "Prime" in item:
 
            #special cases for prime fights.
 
            name = item[6:]
 
            config.feral_list["Prime"] = name
 
        elif "backup" in item:
 
            name, ind = item.split(" backup ")
 
            config.feral_list[int(ind)] = name
 
        else:
 
            print("not sure about this one")
 
            print(item)
 
            continue
 
    print(config.feral_list)
 
 
 
       
 
def target_feral(target_mode):
 
    '''Select a target from the Things list. target_mode 0 broadcasts to all
 
    players who react to ooc targeting messages. Target mode 1 is player only.
 
    '''
 
    # Check that there's something in the list:
 
    if len(config.feral_list) == 0:
 
        #print("Nothing in feral_list")
 
        return None
 
    # Check if the target feral is still there:
 
    if config.current_target in config.feral_list.keys():
 
        #print("Still targeting feral: {0} {1}".format(config.current_target, config.feral_list[config.current_target]))
 
        return None
 
    # Determine if the feral is a priority target based on its name:
 
    for ii in config.feral_list.keys():
 
        for item in config.feral_priority:
 
            if item in config.feral_list[ii]:
 
                config.current_target = ii
 
                #print("targeting {0} {1}".format(ii, config.feral_list[ii]))
 
                if target_mode == 1:
 
                    command = ["#send ooc !target {blarg}.".format(blarg=ii)]
 
                else:
 
                    command = ["#send target {blarg}. ".format(blarg=ii)]
 
                output(ses, command)
 
                return
 
    # Otherwise just target the lowest numbered feral:
 
    feral = config.feral_list.keys()[0]
 
    if feral != config.current_target:
 
        config.current_target = feral
 
        if target_mode == 1:
 
            command = ["#send ooc !target {blarg}.".format(blarg=feral)]
 
        else:
 
            command = ["#send target {blarg}. ".format(blarg=feral)]
 
        output(ses, command)
 
 
 
 
 
def create_player_list(players):
 
    temp_list = players.split(",")
 
    config.player_list = []
 
    for item in temp_list:
 
        item = item.split("] ")[1]
 
        item = item.strip()
 
        if "[" in item:
 
            item = item.split("[")[0]
 
        # Ignore "me" and add other players to list
 
        if not re.match(config.player, item):
 
            config.player_list.append(item)
 
    config.player_list.append(config.player)
 
    #print(config.player_list)
 
 
 
 
 
   
 
def battle_timer(status):
 
    if status == "started":
 
        config.battle_started = datetime.datetime.now()
 
    else:
 
        a = datetime.datetime.now()
 
        try:
 
            diff = a - config.battle_started
 
        except NameError:
 
            #print("Doesn't look like the battle started!")
 
            return
 
        command = ["#showme Battle Duration: {{{0}}}".format(diff)]
 
        #print("TEST #line log {{stats_{0}}} {1}".format(config.player.lower(), diff))
 
        output(ses, command)
 
   
 
 
 
# =============================================================================
 
# misc stuff
 
# =============================================================================
 
def daily_done():
 
    '''saves time of completion of last daily'''
 
    config.next_daily = datetime.datetime.now() + datetime.timedelta(hours=18)
 
    write_vars()
 
   
 
   
 
def daily_timer():
 
    #print(config.next_daily)
 
    if config.next_daily == 0:
 
        command = ["#showme No daily data saved!"]
 
        output(ses, command)
 
        return
 
    time_diff = config.next_daily - datetime.datetime.now()
 
    hours, rem = divmod(time_diff.total_seconds(), 3600)
 
    mins, secs = divmod(rem, 60)
 
    #print("Time check: {0}:{1}:{2}".format(hours, mins, secs))
 
    if time_diff.total_seconds() <= 0:
 
        command = ["#var next_daily Ready to get next daily mission.", "#showme Go get your daily!"]
 
    else:
 
        a = "{0}h {1}m {2}s left until daily available.".format(hours, mins, secs)
 
        command = ["#var next_daily {0}".format(a), "#showme {0}".format(a)]
 
    output(ses, command)
 
 
 
 
 
def edit_descrip(location):
 
    msgs = config.descriptions[config.player.lower()]
 
 
 
    #delete current description and write new descrip:
 
    if "home" in location:
 
        command = msgs["home"]
 
    elif "away" in location:
 
        command = msgs["away"]
 
    output(ses, command)
 
 
 
 
 
def gothere(location):
 
    if location.lower() in ["n","e","s","w","ne","nw","se","sw","u","d"]:
 
        command = ["#send {loc}".format(loc=location)]
 
    elif location in config.places:
 
        command = config.places[location]
 
    else:
 
        command = ["#showme I don't know how to get there!"]
 
    output(ses, command)
 
 
 
 
 
def party_invite(person, status):
 
    if status == 2:  # open to invites
 
        command = ["#send pinvite {per}".format(per=person)]
 
    elif status == 0:  # closed to invites
 
        command = ["#send page {per}=AUTOMSG: Sorry, not inviting at present".format(per=person)]
 
    elif status == 1:  # invite if trusted
 
        if person in config.party_list:
 
            command = ["#send pinvite {per}".format(per=person)]
 
        else:
 
            command = ["#send page {per}=AUTOMSG: Sorry, you are not in my autoinvite list, please wait a few moments.".format(per=person)]
 
    output(ses, command)
 
 
 
 
 
def party_list(task, person):
 
    a = str(config.party_list)
 
    if task == "add":
 
        if person not in config.party_list:
 
            config.party_list.append(person)
 
            command = ["#showme {per} added to party list!".format(per=person)]
 
        else:
 
            command = ["#showme {per} already in the party list! {check}".format(per=person, check=a)]
 
    elif task == "del" and person in config.party_list:
 
        try:
 
            config.party_list.remove(person)
 
            command = ["#showme {per} removed from party list!".format(per=person),
 
                      "#showme {check}".format(check=str(config.party_list))
 
                      ]
 
        except:
 
            command = ["#showme Couldn't find this person. {check}".format(check=a)]
 
    elif task == "check":
 
        command = ["#showme {check}".format(check=a)]
 
    else:
 
        command = ["#showme What? {task}".format(task=task)]
 
    write_vars()
 
    output(ses, command)
 
 
 
 
 
# =============================================================================
 
# Output to tintin
 
# =============================================================================
 
 
 
# Take the input commands and pass them to tt++
 
def output(ses, command):
 
    for item in command:
 
        #print("#py tintin ({ses}) #showme Sending: {cmd}".format(ses=ses, cmd=item))
 
        print("#py tintin ({ses}) {cmd}".format(ses=ses, cmd=item))
 
</pre>
 
 
 
config script:<br>
 
<pre>
 
#! /usr/bin/env python
 
global __DBNAME__
 
 
 
debug = False
 
hp = 90
 
en = 90
 
submit = 10
 
next_daily = 0
 
feral_list = {}
 
current_target = 0
 
player_list = []
 
player_stats = []
 
pets_stats = []
 
feral_stats = []
 
feral_pets_stats = []
 
feral_priority = ['Prime', 'Goo Girl', 'Perplexing', 'Front and Center', 'Regenerator']
 
 
 
places = {"Ice_Caves" : ["#20 e", "#2 s", "#2 e", "#1 s", "#3 e", "#1 n",
 
                        "#5 e", "n", "e", "n", "e", "n", "e", "n", "e",
 
                        "n", "e", "n", "e", "n", "1", "e", "e", "#3 n",
 
                        "e", "b", "n", "d"],
 
 
 
          "Scrublands" : ["#20 e", "s", "#2 e", "s", "#3 e", "n",
 
                          "#5 e", "n", "e", "n", "e", "n", "e", "n", "e",
 
                          "n", "e", "n", "e", "n", "1", "s", "sw", "e", "s",
 
                          "s", "s", "w", "w", "s"],
 
 
 
          "Peaks" : ["w","n","n","n","e","n","n","w"]
 
        }
 
 
 
 
 
anwen_msg = {"home" : ["#send editplayer", "2",
 
                  ".del 1", ".del 1", ".del 1", ".del 1",
 
                  ".del 1", ".del 1", ".del 1", ".del 1",
 
                  "A small ornate bell hangs from a ribbon attached above Anwen's tailbone. It emits an etherial light.",
 
                  "On close inspection it has the word 'Yes' scribed in it in flowing letters.",
 
                  "[if [player] is [looker]][line break][player]'s current mutation-strains are:[line break]head: [stat Mutation/head of [player]][line break]torso: [stat Mutation/torso of [player]][line break]arms: [stat Mutation/arms of [player]][line break]legs: [stat Mutation/legs of [player]][line break]skin: [stat Mutation/skin of [player]][line break]ass: [stat Mutation/ass of [player]][line break]groin: [stat Mutation/cock of [player]][end if]",
 
                  ",end", "q"
 
                ],
 
            "away" : ["#send editplayer", "2",
 
                  ".del 1", ".del 1", ".del 1", ".del 1",
 
                  ".del 1", ".del 1", ".del 1", ".del 1",
 
                  "Anwen wears a small, black, tight-fitting shirt adorned with The Red Court logo. A pair of tight shorts serve to cover Anwen's modesty.",
 
                  "A small ornate bell hangs from a ribbon attached above Anwen's tailbone. It emits an etherial light. On close inspection it has the word 'yes' scribed in it in flowing letters.",
 
                  "Whatever might that mean?",
 
                  "[if [player] is [looker]][line break][player]'s current mutation-strains are:[line break]head: [stat Mutation/head of [player]][line break]torso: [stat Mutation/torso of [player]][line break]arms: [stat Mutation/arms of [player]][line break]legs: [stat Mutation/legs of [player]][line break]skin: [stat Mutation/skin of [player]][line break]ass: [stat Mutation/ass of [player]][line break]groin: [stat Mutation/cock of [player]][end if]",
 
                  ",end", "q"]
 
        }
 
</pre>
 
 
 
 
 
 
 
I hope this is useful and wish you all the best.
 
Your friend, Anwen :3
 

Revision as of 09:21, 1 May 2020

Install

Required packages (for Debian Linux)

Become root, either via sudo -i or some other method.

Run all of these commands as root (yes, bash is probably pre-installed, this is just making sure).

apt-get update
apt-get install tmux tintin++ bash git nano \
libcommon-sense-perl \
libdatetime-perl \
libdatetime-event-sunrise-perl \
libfile-changenotify-perl \
libfile-pid-perl \
libjson-perl \
libtest-lwp-useragent-perl \
libpath-class-perl \
libtime-duration-perl

Type exit (or ctrl+d) to end the session if you opened a new root session for this.

FIXME: Are Getopt::Long and Term::ANSIColor built in, there don't seem to be Debian packages.

Download the script package

Next, run these commands as your normal user account (not root). Replace any bold names with file-paths of your choosing. Also remember that once a path exists, tab-complete often works for typing it out.

cd AnywhereYouWant
git clone https://gitlab.com/inutt/flexible-survival-ui.git fs-ui
chmod +x fs-ui/flexible_survival
fs-ui/flexible_survival

Very minimal config.json

nano fs-ui/config.json

Above nano is used to edit the config file, if you prefer a different editor use that. The launcher script should have setup the config file to be readable only by admins (root) and your exact user account.

  • "character": "", and
  • "password": "", MUST be filled out.

JSON ignores non-printing 'whitespace' and requires that a key/value sets (contained in { } and called an object) have values in the middle separated by commas, but NO comma at the end. {"character": "USER", "password": "PASSWORD"}. Any values you don't want to change can be deleted. Thus this might be an example minimal configuration file:

{
    "fs": {
       "character": "YOURUSER",
       "password": "YOURPASS"
    }
}

In the above the extra commas after the password line, and that closing } after the "fs" key have been removed. Again, the whitespace doesn't matter, so it could also be just (with no spaces even).

{"fs":{"character":"YOURUSER","password":"YOURPASS"}}

Setting where the window splits to panes

The numbers in the tmux section are how you configure the split of the window. You'll probably want to keep them and change them to suit your own needs.

    14 chat
 ------+-----------
 status|
 ------|   main
 map 27|
 64=>  |
   "chat_height": 14,
   "map_width": 64,
   "map_height": 27,
   "status_height": 16

Note: status_height doesn't actually set the height. It tells the status update script how tall this section is so that it might omit some spacing or features to fit.

Final config.json

You probably also want to set "data_dir": "SOMETHING", which is where your map data and log files will be stored. This won't be created for you, so make sure you create it first. E.G.

mkdir "~/Documents/Flexible Survival Logs"

Then your config.json file might look something like this

nano fs-ui/config.json
{
    "tmux": {
        "session_name": "Flexible Survival",
        "chat_height": 14,
        "map_width": 64,
        "map_height": 27,
        "status_height": 16
    },
    "fs": {
        "character": "YOURUSER",
        "password": "YOURPASS",
        "data_dir": "~/Documents/Flexible Survival Logs"
    }
}

If you're using WSL this gets more complicated. "/mnt/c/Users/WindowsAccountName/My Documents/Flexible Survival Logs" might work for most. If it doesn't, talk to whomever maintains the PC. Tab-completion is really helpful here... mkdir /mnt/c/User (TAB) and then hit tab a couple more times to get a good guess at user account and My Documents locations to start in.

With that setup you SHOULD be able to (after setup!)

Get updates

cd fs-ui
git pull

This can be run any time (in where-ever you had the download stored). If there are any updates or bugfixes; though you might need to update your config.json file to use new features.

Connect

  • fs-ui/flexible_survival

When running Ctrl+B (arrow key) (hold down control, tap b, release both; then press an arrow key) can be used to move the input-focus between panes (text areas within that window). Up and Down arrow keys are the ones you'll care about. Up to go to the chat channels, down to go back to muck input. You type all commands in the main muck window, even though the text shows up above.

Windows 10 WSL

If you'd like to use TinTin++ on Windows, installing a WSL based distribution such as Debian is highly recommended. If you have experience with a different distribution maintaining a server, including getting perl5 dependencies installed based on error messages, then go ahead and go with that. Debian has been selected here for being focused on Freedom, Liberty, and Stability, as well as generally providing clear directions for upgrades.

Note: Windows 10 S tries to be a "safe" OS that restricts user freedom, and thus won't run even WSL. They also offer an upgrade, for a fee, to normal-freedom Windows 10 (no S).

Please follow Debian's official guide for installing on WSL. It will likely have links updated as versions of things change.

History

[TinTin++] is the result of almost 30 years of development by a series of programmers. While an absolute dinosaur of a computer from the era of it's origin in the mid 1990s probably couldn't run it today, just about anything from the last 20 years probably can.

Several older versions of this wiki page exist (updated during 2013 and 2015) with the final version of that series updated on 2015-08-25T14:09:09 you might find Anden's examples useful if interested in battle tactics, though they're written assuming python2 (which is no longer supported); while Inutt's code repository uses some perl5 helpers that could be replaced or omitted entirely without breaking the basic multipane functionality. (They help produce the formatted status window and optionally near realtime weather.)

Inutt, one of the coding wizards for FS, has a nice setup for TinTin that's published on their GitLab page. Ketsueki made some small contributions (currently a pull request) to make it more suitable for users with different terminal sizes. Though it does expect a computer screen capable of displaying at least 120 columns of characters across (in that case a split of about 29 for the map and status area, and thus 90 or so for the main text area is recommended). If you're on a 1080p+ monitor, using a normal Graphical User Interface (E.G. Windows, OS X, anything else that runs a web browser) and using a full-screen "terminal" program of any sort (find one you like for your OS) you probably do have that many columns.