updated to kiooeht

This commit is contained in:
illuminatedwax 2011-06-26 16:42:19 -05:00
commit 88f548bc68
104 changed files with 8294 additions and 1760 deletions

7
.gitignore vendored
View file

@ -2,5 +2,10 @@ logs/*
build/*
profiles/*
tmp/*
tutorial/*
irctest.log
*.pyc
*.pyc
pesterchum.js
quirks/*
!quirks/defaults.py
*.pkl

View file

@ -7,6 +7,68 @@ Visit https://github.com/illuminatedwax/pesterchum for git access and source cod
CHANGELOG
---------
### 3.14.2
* Individually turn quirks on and off - Kiooeht [evacipatedBox]
* More canon trollian theme timeline indicators - [binaryCabalist]
* By mood chum sorting - Kiooeht [evacipatedBox]
* Chum groups - Kiooeht [evacipatedBox]
* Turn logging on and off - Kiooeht [evacipatedBox]
* Customizable idle time - Kiooeht [evacipatedBox]
* Different sound for memos - Kiooeht [evacipatedBox]
* Animated smilies - Kiooeht [evacipatedBox]
* Delete profiles - Kiooeht [evacipatedBox]
* Customize minimize and close button actions - Kiooeht [evacipatedBox]
* Receive notices from services you're talking to - Kiooeht [evacipatedBox]
* Automatically turn off quirks when talking to bots - Kiooeht [evacipatedBox]
* Rearrange options menu, make tabbed - Kiooeht [evacipatedBox]
* Rearrange memos window for readability - Kiooeht [evacipatedBox]
* Give voice to memo users - Kiooeht [evacipatedBox]
* Theme checking - Kiooeht [evacipatedBox]
* Display (De)OP/Voice messages in memos - Kiooeht [evacipatedBox]
* Advanced Mode: Alter IRC user mode - Kiooeht [evacipatedBox]
* Logviewer chum search - Kiooeht [evacipatedBox]
* Logviewer log search - Kiooeht [evacipatedBox]
* Set server and port from command line - Kiooeht [evacipatedBox]
* Invite-only memos, invite chums to memos - Kiooeht [evacipatedBox]
* Check Pyqt4 and pygame are installed and correct versions - Kiooeht [evacipatedBox]
* Advanced Mode: View memo (channel) modes - Kiooeht [evacipatedBox]
* Quirk groups - Kiooeht [evacipatedBox]
* CTCP Version reply - Kiooeht [evacipatedBox]
* Check for Pesterchum updates - Kiooeht [evacipatedBox]
* Memo OP options: Secret, Invite-only, Mute - Kiooeht [evacipatedBox]
* Notify user if channel blocks message - Kiooeht [evacipatedBox]
* Bug reporter - Kiooeht [evacipatedBox]
* Python quirks (users can create own quirk functions) - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Incorporate support for the new randomEncounter - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Only GETMOOD for people online (less spam!) - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Quirk tester in quirk window - Kiooeht [evacipatedBox] (Idea: [alGore])
* Show and support giving kick reasons - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Make adding quirks into multi-page wizard - Kiooeht [evacipatedBox]
* Flash the taskbar on new messages - Kiooeht [evacipatedBox]
* Third beep sound for when your initials are mentioned in memos - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* Ctrl + click to copy links - Kiooeht [evacipatedBox]
* Say something when server is full - Kiooeht [evacipatedBox]
* Ping server if no ping from server to test connection - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
* MSPA comic update notifier - Kiooeht [evacipatedBox]
* Volume control - Kiooeht [evacipatedBox]
* Bug fixes
* Logviewer updates - Kiooeht [evacipatedBox]
* Memo scrollbar thing - Kiooeht [evacipatedBox]
* Time arrows in enamel - Kiooeht [evacipatedBox]
* Quirk order actually works - Kiooeht [evacipatedBox]
* Stay in memos on profile switch - Kiooeht [evacipatedBox]
* Auto rejoin memos on reconnect - Kiooeht [evacipatedBox]
* De-Op in memos correctly - Kiooeht [evacipatedBox]
* Don't blow up if someone's not using Pesterchum in a memo - Kiooeht [evacipatedBox]
* Make 'logs' and 'profiles' directories if non-existant - Kiooeht [evacipatedBox]
* Don't split messages in bad places - Kiooeht [evacipatedBox]
* Chumhandles must match EXACTLY to register mood changes - Kiooeht [evacipatedBox]
* Menu bar text colour correct when default system colour isn't black - Kiooeht [evacipatedBox]
* End all colour tags and restart them on split messages - Kiooeht [evacipatedBox]
* Chat input box right-click menus - Kiooeht [evacipatedBox]
* Don't overflow random colours into colourless messages - Kiooeht [evacipatedBox]
* Only open links on left click - Kiooeht [evacipatedBox]
### 3.14.1
* Pesterchum 3.14 - illuminatedwax [ghostDunk]
* Art - Grimlive [aquaMarinist]
@ -15,17 +77,16 @@ CHANGELOG
* Quirks reverse() function - illuminatedwax [ghostDunk]
* Timestamps - Kiooeht [evacipatedBox]
* Logviewer - Kiooeht [evacipatedBox]
* Quirk ordering - alGore
* # of users in a memo - alGore
* Quirk ordering - [alGore]
* # of users in a memo - [alGore]
* @links to users - illuminatedwax [ghostDunk]
* Support for REPORT and ALT to calSprite built in
BUG FIXES:
* mixer bug fixed
* "flags" bug fixed
* incorrect characters in memos no longer break log file names
* memos now do not break on case-sensitivity
* fixed QDB address
* now lines too long to send in a single message are split up correctly
* quirk replace bug fixed
* pesterClientXXX profiles no longer saved
* Support for REPORT and ALT to calSprite built in - illuminatedwax [ghostDunk]
* Bug fixes:
* mixer bug fixed
* "flags" bug fixed
* incorrect characters in memos no longer break log file names
* memos now do not break on case-sensitivity
* fixed QDB address
* now lines too long to send in a single message are split up correctly
* quirk replace bug fixed
* pesterClientXXX profiles no longer saved

87
PYQUIRKS.mkdn Normal file
View file

@ -0,0 +1,87 @@
Python Quirk Functions
===============
Table of Contents
-----------------
1. Introduction
2. Create A Module
3. Functions In A Module
4. Command Requirements
5. Completed Quirk Function
Introduction
---------------
Over the course of this short tutorial you will learn:
* How to create your own Quirk Functions
* VERY basic Python syntax
You will not learn:
* How to write Python
* How to bake a cake
Throughout this tutorial there will be
<pre>
Instructions in special boxes.
If you follow the instructions in these boxes, by the end of this tutorial
you will have recreated the default reverse() Quirk Function.
</pre>
Create A Module
-------------------
All Quirk Function Modules should be created in the 'quirks/' directory. File names <b>must</b> end in '.py'.
You can have multiple Quirk Functions per Module.
Each Module can also have a 'setup' function which will be called once, the moment the Module is loaded.
<pre>
Create 'reverse.py' in the 'quirks/' directory.
</pre>
Functions In A Module
--------------------------
If you've ever done programming before, you should know what a function is. If not, I suggest picking up a good programming book (or e-book).
In Python, function syntax looks like this:
def function_name(myvar1, myvar2):
'def' is used to declare that this is a function, and 'function_name' is obviously the name of your function.
'myvar1' and 'myvar2' are variables coming into your function. For most of your functions, the only variable being passed will be 'text'.
In Python, curly braces ({}) are not used to declare the beginning and end of a function. Instead, a colon (:) is used to declare the beginning of a function. After that, indentation is used to declare the body and end of a function.
<pre>
def reverserep(text):
return text[::-1]
</pre>
Command Requirements
------------------------
For a function to be registered as a Quirk Function, it must conform to three simple rules:
1. It must have a command name.
2. It must take exactly one arguement.
3. It must return a string.
What is meant by having a command name, is that a name for the Quirk Function has to be defined. This is done by defining the 'command' variable for a function.
function_name.command = "name"
<pre>
reverserep.command = "reverse"
</pre>
Completed Quirk Function
---------------------------
Below is the completed, fully working, reverse Quirk Function. After it I will break down the pieces of each line.
<pre>
def reverserep(text):
return text[::-1]
reverserep.command = "reverse"
</pre>
As stated before, to start a function, you need to use the keyword 'def'. All Quirk Functions must take exactly one argument (in this case 'text').
In this example, the text is reversed and returned all in one line. 'text[::-1]' is the Pythonic way of reversing a list or string.
The last line is the most important part. This tells Pesterchum to call this function whenever 'reverse()' is used in a quirk.

781
README.mkdn Normal file
View file

@ -0,0 +1,781 @@
Welcome to Pesterchum 3.14.1!
=============================
WHAT'S NEW?
-----------
* Quirks now have a lower(), scramble(), and reverse() function!
* Timestamps - check your Config!
* Logviewer - View logs right in Pesterchum!
* Quirk ordering - order your quirks so they work right!
* # of users in a memo - You can now see how many users are in a memo.
* @links to users - typing @ before user's name creates a link
that will pester them!
* Support for REPORT and ALT to calSprite built in -
If someone is bothering you, or a canon handle is idle, or
for whatever reason, right click their name and go to "Report"
to report them to a moderator.
If you want to talk to an alt canon handle, just right click
the username!
if you have an alt handle, register it with calSprite!
Here's some tips to help you get started:
-----------------------------------------
- You can import your old Pesterchum contacts by going to
CLIENT->IMPORT and opening your pesterchum.cfg file. This is usually
in the 2.5 base directory or in Tinychum's data folder.
- Some themes can be confusing if you haven't used the program
already! Some hints:
* Trollian: Moods are set by clicking the timelines, and you
can add chums by clicking "Chumproll." Moods correspond to the troll
that would most likely exhibit them. You can go offline by hitting the
"Timelines" menu bar.
* Gold: Add chums by hitting the two chumpeoples in the upper left
corner. Go offline by clicking the "CHUMHANDLE:" label.
* Enamel: Add chums by hitting the "CHUMROLL" label. Go offline by
clicking the upper left hand corner.
- Right-click is your friend! There are useful right click
options on the chumroll, by clicking the chumhandle in a conversation,
online userlist, or the list of memo browsers.
Cool features:
--------------
- Importing from old PC. It can already do your chumlist, soon it will
import your quirks from 2.5 and TC as well!
- Profile switching. Instantly switch profiles, loading your color and
quirks with it.
- Theme switching and creation. So far this comes with a few official
themes! But you can also make your own: just make a new directory in
the themes folder with the proper images and style.js file. The
style.js file will be documented soon, but feel free to poke at it.
- Memos. Memos that are a lot more like the ones in the comic and
allow you to appear at multiple times in one chat.
- Quirks: Prefix, suffix, simple replace, regexp replace (like in
2.5), random replacement, and an auto-mispeller :P
- Chum groups. Organize your chums into collapsible groups for easy
management.
- Block/user list
- Add/block chums directly from a conversation, the userlist, or memo
userlist.
- Timestamps saved in logs and shown in conversations if wanted.
- Logging. Logs are output in bbcode (for easy forum posting), html,
and plain text.
- Logviewer for easy log reading inside Pesterchum
- Idling. You can set yourself idle manually, and the computer will
set it for you after a configurable amount of time.
- Improved /me. Any letters immediately following /me will be
processed correctly. e.g. /me'd rather be fishing -> -- ghostDunk'd
[GD'D] rather be fishing --
- Hyperlinks! Now if someone types http://whatever it will turn into a
link you can just click and follow. No more copy/paste.
- Memo links. Link your friends to your memos.
- Smilies. We've added about 30-40 smilies from the forums. There is a
list later on in this readme.
- Submit quotes directly to the Pesterchum QDB!
FA%
---
<b>Q:</b> Norton says it has a virus and then deletes it!<br>
<b>A:</b> Read this helpful Norton FAQ:
Alright, here's a guide to by-passing Norton:
* First, to download Pesterchum:
1. Make sure you're on a Moderator account. Moreso for the Norton steps than these ones.
2. Download the .zip file, not the .exe file.
3. Unzip the .zip file onto memory. Pesterchum should now be installed.
* Now, to by-pass Norton:
1. Make sure you're still on a moderator account.
2. Open up Norton.
3. Click on 'Settings' up in the upperright hand corner.
4. Click on 'Anitivirus', off to the upper left. It has a small image of a needle or something similar off to it's side.
5. There's a word that reads 'SONAR protection' halfway to the bottomleft. Off to it's right, there's a bar that's half green. Click on the bar.
6. It will warn you about turning off SONAR. Have it set to turn back on when the system restarts.
7. If done properly, the background for the main page of Norton(what you saw on steps 2-3) has turned an apocaliptic red. Feel free to close Norton now. Keep in mind to stay off suspicious online sites now.
8. Open up Pesterchum, and let the chummy convos begin.
* When finished:
1. Log off of Pesterchum. LOG OFF, NOT CLOSE IT.
2. Then, you can either shut off your comp, and Norton will re-enable SONAR, or you can repeat steps 1-5, except turning the red bar green. If done right, Norton will be it's happy color again.
3, Keep in mind that you must repeat all of this(other than the download) every time you want to get on Pesterchum.
* Hope this is helpful!
(This guide brought to you by the slightly combined efforts of empireomega and Xanaomin)
------------------------------------------------------------------------------------
<b>Q:</b> I can't connect because my school/university/network/stolen wifi is blocking my connection! OR I can't seem to connect to the server at all and I'm not running any firewalls!<br>
<b>A:</b> Edit your pesterchum.js file. Open it up in notepad or something, and then edit the beginning so it looks like this:
{"port": "1413", ....
where the .... is the rest of the gobbledygook there.
------------------------------------------------------------------------------------
<b>Q:</b> The mood buttons on Pesterchum 6.0 don't match up to what it sets your mood to! What gives?<br>
<b>A:</b> The mood names are just there to look canon. It is intentional.
------------------------------------------------------------------------------------
<b>Q:</b> I'm appearing as offline to 2.5 users/other users appear the wrong
mood? What's happeninggggg<br>
<b>A:</b> The 2.5 people decided to change the mood protocol. When I made
this program, I decided to go with Tinychat's original protocol (and
extend it). So some moods will appear wrong between 2.5
users. (*COUGH*tell them to switch to 3.14*COUGH*)
------------------------------------------------------------------------------------
<b>Q:</b> Pesterchum 2.5 users don't get my /me messages correctly!<br>
<b>A:</b> That's because they implemented the /me command differently.
------------------------------------------------------------------------------------
<b>Q:</b> Can we resize the main window?<br>
<b>A:</b> No. This is done so we can offer more flexible UI creation. It's a
lot easier to make themes that look canon this way.
------------------------------------------------------------------------------------
<b>Q:</b> Can we have different chum rolls for different users?<br>
<b>A:</b> No. Instead what we now have crum groups to organize people.
------------------------------------------------------------------------------------
<b>Q:</b> Can we delete profiles?<br>
<b>A:</b> Yes. Go to the profile switcher, choose a profile and press DELETE.
------------------------------------------------------------------------------------
<b>Q:</b> You should make it so you can ban specific time frames in memos.<br>
<b>A:</b> This was too complicated to implement, and I don't have the UI
quite figured out. This will probably go in a future update.
DOCUMENTATION
-------------
STARTING
--------
If this is your first time running Pesterchum 3.14, you need to create
a new profile. Just type in your chum handle in the box and click the
color swatch to pick your color. Check the "default" checkbox to make
this your default profile.
BASIC PESTERING
---------------
To begin pestering, first click the "ADD CHUM" button and type in
their pester handle. The handle must be all lower case except for one
capital letter. Once you've added that person, they will appear on
your chumroll. You can double click to begin pestering them, or
right-click to bring up a menu where you can pester them, block them,
or remove them from your chumroll. (Or you can select them and hit
"enter" OR hit the "PESTER" button.)
Once you begin pestering somebody (or they begin pestering you), it
will bring up the conversation window. Here you can type to your
chum. Also remember that if you right-click on the area just above the
Pesterlog, it will bring up a list of options: Quirks Off will turn
your quirks off, Add Chum will add this chum to your list, and Block
will block them. (Those last two options are useful if you are being
pestered by someone you don't have on your list yet!)
While pestering your chum, here are some useful features:
* Type /me to create a system message. "/me facepalms." will generate:
-- ghostDunk [GD] facepalms. --
You can also append 's after /me like so: "/me's computer exploded."
-- ghostDunk's [GD'S] computer exploded. --
In fact, any characters you type after a /me before the space will
be added: "/meing is the Ghost Nation's official pastime."
-- ghostDunking [GDING] is the Ghost Nation's official pastime. --
* Color tags! If you feel the need to talk about The Green Sun or add
some appleberry blast to your conversation, just use color
tags. These work like in TC 1.5: <c=(color)>colored text</c>. But in
PC 3.14, you can use type your color in a lot of different ways:
- You can use the familiar r,g,b method:
"<c=0,255,0>The Green Sun</c>"
- You can use HTML tags:
"<c=#7f7f7f>DURR I'M KARKAT AND I'M A HUGE IDIOT</c>"
- You can even use plain color names:
"<c=red>D4V3 TH1S 1S SO D3C4D3NT</c>"
(list: http://www.w3schools.com/css/css_colornames.asp)
- You don't even have to add the </c> if you are lazy. Just use a
new color tag whenever you want to change colors and PC 3.14 will
add the extra tags for you.
* URLS (anything with http:// in front of it) will automatically be
detected and made into a link you can CLICK.
* You can also link people to memos by typing "#" and the name of the
menu like so: #R41NBOW_RUMPUS_P4RTYTOWN
Clicking the link will open up the memo select menu.
* Smilies! There are a list of smilies at the end of this document;
they are based on the MSPA Forum smilies.
* Don't worry about your quirks screwing up any of the above: PC will
apply your quirks AFTER it figures out color codes, links, smilies, etc.
* Pressing the up arrow will cycle through a history of your comments,
so if you want to retype something, you can pull it up.
* You can submit directly to the Pesterchum Quote Database! If you
have a particualarly awesome conversation, you can submit it to the
database by simply highlighting the good part of the conversation,
right clicking it and choosing "Submit to Pesterchum QDB!"
MEMOS
-----
One of the most interesting features to make was the memos, and make
them as close to the comic as I could without actually inventing time
travel. So here is the TIME TUTORIAL:
* <b>Joining:</b> When you go CLIENT->MEMOS, you'll see a list of memos pop up
-- those are memos people already have open. To join one, just
highlight one of them. If you want to make a new memo, just type it in
the input. If you'd like to make it secret, so that it doesn't appear
in the list, check "HIDDEN CHANNEL". Then, choose what timeframe you
want to appear to be in. So if you wanted to be in the future, you
could move the slider to the right. You can also enter the time
manually. Then hit JOIN.
* <b>Explaining time:</b> Time in memos, unlike Homestuck, will not be relative
to your position. That is, if you choose 4:13 in the future, you will
not see someone who has set their time as "current" (or "0") in the
past: you will see them as "current" and yourself as "future." This is
because we do not have time travel! Memo time setting is basically an
RP mechanic: you are pretending to be from the future! It will also
help keep everyone straight: everyone will see the same thing!
* <b>The time slider:</b> The slider shows your current position in the time
stream. If you want to change your time frame, simply move the slider
(or type a time in) and hit GO. This will open a new time frame, and
the next time you type a message, the memo will show that you've
responded to it in that time frame. You can now switch between your
time frames simply by clicking the arrows in the right hand
corner. (THIS COMES IN HANDY IF YOU WANT TO ARGUE WITH YOURSELF.) You
can have any number of open time frames, and the program will number
them in the order in which you open them (like in the comic). You can
have one of your time frames cease responding to the memo by hitting
"CLOSE." If you open that time frame again, the program will remember
the number it originally gave it. If you want to be mysteeeeeeeerious,
you can type in "?" and you will appear as ???.
* <b>The memo viewer list:</b> To the right is a list of people currently
browsing the memo. A shade icon next to their name means they are the
"operator" of the memo: meaning they can kick ("ban") people from the
memo and make other people operators as well. A "ban" is not permanent
(like in the comic), and the program will ask if you want to reconnect
to the memo. You kick and op people by right clicking their name in
the window. You can also add them to your chumroll!
* <b>Inviting people to your memo:</b> You can link to a memo by simply typing
"#nameofmemo" in any conversation or memo window. So you can say:
CG: NOW YOU, ME, AND EGBERT NEED TO HAVE A CHAT.
CG: CLICK IT.
CG: #FRUITYRUMPUSASSHOLEFACTORY
and it will appear as a link that you can click, which will open the
memo chooser window.
CLIENT MENU
-----------
###OPTIONS:
* <b>Chum List</b>
* <b>Hide Offline Chums:</b> Turning this option on will hide all offline chums
off your chumroll.
* <b>Show Empty Groups:</b> Turning this option on will show empty groups.
* <b>Show Number of Online Chums:</b> Show number of online chums in each group.
* <b>Sort Chums:</b> How would you like your chums sorted?
* <b>Conversations</b>
* <b>Time Stamps:</b> Turning this on will show timestamps in your chats.
* <b>12/24 hour:</b> Formatting for timestamps. Whether you want them in 12 or
24 hour time.
* <b>Show Seconds:</b> Turning this on will show the seconds in your timestamps.
* <b>Show OP and Voice Messages in Memos:</b> Whether or not you would like
to see messages when people gain/lose OP or Voice.
* <b>Use animated smilies:</b> To animate or not to animate.
* <b>Interface</b>
* <b>Tabbed Conversations:</b> Turns tabbed conversations on and off. Don't
worry if you do this in the middle of a conversation, PC will save
them for you.
* <b>Minimize:</b> What do you want the minimize button to do?
* <b>Close:</b> What do you want the close button to do?
* <b>Sound</b>
* <b>Sounds On:</b> Uncheck to shut it the fuck up.
* <b>Pester Sounds:</b> Uncheck to only turn off Pester sounds.
* <b>Memo Sounds:</b> Uncheck to only turn off Memo sounds.
* <b>Memo Mentions:</b> Check to have a separate noise when your initials
get mentioned in a memo.
* <b>Logging</b>
* <b>Log all Pesters:</b> Log one-on-one chats.
* <b>Log all Memos:</b> Log everything said in memos.
* <b>Log Time Stamps for Pesters</b>
* <b>Log Time Stamps for Memos</b>
* <b>Idle/Updates</b>
* <b>Minutes before Idle:</b> How long before you should be considered idle.
* <b>Check for Pesterchum Updates:</b> How often to check for updates
to Pesterchum.
* <b>Check for MSPA Updates:</b> Check the MSPA site for updates to comics.
* <b>Theme</b>
* <b>Pick a Theme</b>
###MEMOS:
Opens the Memo list as above.
###USERLIST:
Shows a list of all the users that are currently logged onto
Pesterchum. Right-click their names and select "ADD CHUM" to add them
to your chum roll!
###IDLE:
Make yourself an idle chum. You will appear as idle until you
uncheck this box, or if you *actually* go idle (stop using the
computer) for 10 minutes and then come back.
###IMPORT:
Imports your old Pesterchum 2.0, 2.5 and Tinychum chum
rolls. This will also import your old quirks from Pesterchum 2.5.
###RECONNECT:
Forces PC to reconnect to the server.
###EXIT:
noooooooooooooooooooooooo
PROFILE MENU
------------
###QUIRKS:
Opens the quirks menu. More on that below!
###TROLLSLUM:
Opens up the window where you can view people you've
blocked. You can add and remove people to the list from here as well.
###COLOR:
Change your text color here!
###SWITCH:
Switch your profile! You can have any number of profiles, and
PC will save your color, quirks, and theme for that profile. Chumrolls
and block lists are the same for all profiles. Feel free to have
multiple instances of PC running on two or more handles!
HELP MENU
---------
###HELP:
Get taken to a handy dandy tutorial for Pesterchum!
###CALSPRITE:
Open a chat with calSprite (learn more about calSprite below).
###NICKSERV:
Open a chat with NickServ. If you don't know what NickServ is, you don't need to.
###ABOUT:
See which version of Pesterchum you have. Learn about all the awesome people
that helped bring Pesterchum 3.14 to you!
###REPORT BUG:
Report any bugs you come across so we can fix them and make Pesterchum
even better!
CALSPRITE
---------
calSprite is the bot that helps moderate canon handle usage! Simply pester
calSprite with the world "HELP" (turn your quirks off!) and you
will get instructions on how to use calSprite!
QUIRKS
------
There are six kinds of quirks! I'll teach you how to use them all!
(In this section, I will use quotes ("") around things so it's clearer
to see exactly what to type! Don't include these quotes when using
these examples!
Also, note that your quirks will not work until you save them by
hitting "OK" on the Quirk window.
* <b>Prefix/Suffix:</b>
This will put text before or after everything you
say. So for example, we can use prefixes to emulate part of Nepeta or
Equius' quirks:
<pre>
PREFIX: ":33 &lt; "
You type: "*ac twitches her friendly whiskers at ct*"
Result:
AC: :33 &lt; *ac twitches her friendly whiskers at ct*
</pre>
<pre>
PREFIX: "D --&gt; "
You type: "Hi"
Result:
CT: D --&gt; Hi
</pre>
Suffixes work the same way, but at the end of the message:
<pre>
SUFFIX: "!!!"
You type: hey there
Result:
GD: hey there!!!
</pre>
Remember that it doesn't automatically add a space! You'll need to add
it in (see CT and AC examples again!)
* <b>Simple Replace:</b>
This will simply take a set of characters and replace them with other
characters.
* Let's add a quirk to our Nepeta:
<pre>
Replace: "ee" With: "33"
You type: "*ac saunters from her dark cave a little bit sleepy from
the recent kill*"
Result:
AC: :33 &lt; *ac saunters from her dark cave a little bit sl33py from the
recent kill*
</pre>
* Let's add two to Equius:
<pre>
Replace: "loo" With: "100"
Replace: "x" With "%"
You type: "look"
Result:
CT: D --&gt; 100k
You type: "What are you expecting to accomplish with this"
Result:
CT: D --&gt; What are you e%pecting to accomplish with this
</pre>
* Aradia:
<pre>
Replace: "o" With: "0"
You type: "and the reward would be within our reach"
Result:
AA: and the reward w0uld be within 0ur reach
</pre>
Notice that it is CASE SENSITIVE. So in the above case, if you typed
"ABSCOND", it would not replace the "O".
* Sollux:
<pre>
Replace: "i" With: "ii"
Replace: "s" With: "2"
</pre>
* Eridan:
<pre>
Replace: "v" With: "vv"
Replace: "w" With: "ww"
</pre>
* Feferi:
<pre>
Replace: "h" with: ")("
Replace: "H" with: ")("
Replace: "E" with: "-E"
</pre>
* <b>Regexp Replace:</b>
This is a more complex kind of replacement. Regexp stands for "regular
expression", a kind of programming language (yes, it is a language)
used to find and replace text. PC 3.14 also includes a function to
handle capitalization (upper()). If you want to learn it on your own,
I suggest you start with the Python tutorial
(http://docs.python.org/howto/regex.html) since PC 3.14 uses Python's
regexps. Check out V2.5's tutorial too, as that is a pretty good start
as well.
* Let's start with Karkat. Regexps are just like your every day find and
replace: they search for a string that matches what you want to
replace, and replaces it with... the replacement.
<pre>Regexp: "(.)" Replace with: "upper(\1)"</pre>
Three concepts here. Let's look at the regexp. "(.)" has two things
going on. The first is that ".". In regexp speak, "." is the wildcard:
it will match *any* character -- and just one.
The parentheses tell the regexp to *save* what's inside them so you
can put it back when you replace. That's what the "\1" is for -- it
means, "put the match inside parentheses #1 here". You can have any
number of parentheses.
* <b>"upper()"</b> is a function special to PC 3.14 -- it will uppercase
anything inside the parentheses. So in this case, upper will uppercase
"\1" -- which, as you recall is what we found inside the
parentheses. Which was *every* character. So to sum up, it replaces
every character with an uppercase version of that character. WHICH
MAKES YOU TALK LIKE THIS.
* Let's look at Terezi next.
<pre>
Regexp: "[aA]" Replace with: "4"
Regexp: "[iI]" Replace with: "1"
Regexp: "[eE]" Replace with: "3"
Regexp: "(.)" Replace with: "upper(\1)"
</pre>
We already know what the last line does. But what's up with those
brackets? What's their deal? Basically, in regular expressions,
brackets indicate a list of matching characters. So, basically any
single character within the brackets will be matched. In this case,
either "a" or "A" will be matched and replaced with "4," and likewise,
"i" and "I" will be replaced with "1", and "e" and "E" will be
replaced with "3."
Just like there is an <b>"upper()"</b> function, there is also a <b>"lower()"</b>
function. It acts just like <b>"upper()"</b> but instead makes everything
inside the parentheses lowercase. This allows you to do things like:
<pre>
Regexp: "(.)" Replace with: "lower(\1)"
You type: "I AM YELLING"
Result:
GD: i am yelling
</pre>
Along with the upper and lower functions is a <b>"scramble()"</b> function.
The purpose of this function is to randomly scramble anything inside
the parentheses.
<pre>
Regexp: "(\w)(\w*)(\w)" Replace with: "\1scramble(\2)\3"
You type: "hello there"
Result:
GD: hlelo trhee
</pre>
This particular regular expression scrambles all of the letters in
the middle of a word. Notice that the "h" and "o" at the beginning
and end of hello remain in place while the other letters are scrambled.
You should also know that "^" is a special character in brackets. If
placed immediately after the opening bracket (like "[^"), then the
brackets instead match every character *except* the ones in the
brackets. So, for example, if you wanted to have a quirk where you
capitalized all your letters *except* o, you'd do this:
<pre>
Regexp: "([^o])" Replace with: "upper(\1)"
You type: "hello there"
Result:
GD: HELLo THERE
</pre>
You can also specify a *range* of characters inside the brackets, by
using the "-" character. [a-z] will match any lowercase letter. You
can combine them, too: [a-z0-9] will match any digit and lowercase letter.
There are also different shortcuts for character types:
<pre>
\d matches any digit; same as [0-9]
\D matches any non-digit; same as [^0-9]
\s matches any spaces
\S matches any non-space
\w matches any alphanumeric character; same as [a-zA-Z0-9_]
\W matches any non-alphanumeric character; same as [^a-zA-Z0-9_]
</pre>
You can include this inside brackets, too.
There's also a special character, \\b. What \\b does is make sure that
you are at the beginning or end of a word.
* So with that knowledge, let's try Kanaya:
<pre>
Regexp: \b(\w) Replace with: upper(\1)
You type: "i suggest you come to terms with it"
Result:
GA: I Suggest You Come To Terms With It
</pre>
Another feature of regular expressions is the ability to match
*repeated* characters. There are three repeat characters: the "\*", the
"+", "?", and "{m,n}". They work by playing them after the character,
or character type you want to match. (So, you could say "\s+" or ".*")
The "\*" character matches ZERO or more of that character. So, for
example, "f\*" would match "f" and "ff" -- and any other character!
That's right, every character counts as matching it zero times. Yeah,
it's weird. I suggest you use...
The "+" character matches ONE or more of that character. So, if we
wanted to have a character that wanted to elongate their s's so that
they used four 's's every time, like sssso, but didn't want to have
eight s's when using words with double s's, like pass, we'd do this:
<pre>
Regexp: "s+" Replace with: "ssss"
You type: "you shall not pass"
Result:
UU: you sssshall not passss
</pre>
As for the other two, I can't really think of any useful quirks to be
made with them. But to let you know, "?" matches either 0 or 1 of that
character, so "trolls?" would match "troll" and "trolls". "{m,n}"
matches between m and n characters. (If you leave out 'n', any number
of characters more than m will be matched.) So "s{2,4}" will match
"ss", "sss", and "ssss" and that's it.
Now with repeating expressions, we can do something like make EVERY
other WORD capitalized:
<pre>
Regexp: "(\w+) (\w+)" Replace with: "upper(\1) \2"
You type: "this is pretty annoying i bet"
Result:
GD: THIS is PRETTY annoying I bet
</pre>
The \1 matches the first word -- which has been matched because the
word is alphanumeric characters, repeated once or more -- and \2
matches the second word.
Another operator to use is the "|", which will match more than one set
of characters. For example, "black|red" will match "black" or
"red". If you want to match something in the middle of words, you have
to use parentheses: "(black|red) romance" will match "black romance"
and "red romance".
Finally, there are the "^" and "$" characters. Yes, we already did the
"^" character, but this is OUTSIDE of brackets, not INSIDE. "^"
matches the beginning of a message, and "$" matches the end of it. You
can use this to make more sophisticated prefix and suffix
behaviors. For example, if we have a quirk that adds "..." to the end
of all our messages, we can set it up so it doesn't do that if we put
punctuation [?!.] at the end. So:
<pre>
Regexp: "([^?!.])$" Replace with: "\1..."
</pre>
This will match the end of any message as long as it doesn't have
"?", "!", or "." at the end. Then it will replace it with whatever the
last character of the sentence was (remember we're replacing it, so we
have to put it back!) and add "..." at the end.
Careful with the beginning and ending replaces -- if you use more than
one, you may not get what you expect because they will ALL be applied,
one after the other! This is a bug in my opinion, that I plan to fix!
* <b>Random replace:</b>
Just like the regexp replace, except that instead of just one thing to
replace it with, you give it a list. PC will then choose from that
list randomly. So let's say I want to randomly end my sentences with
either "bro" or "dog":
<pre>
Regexp: "$" Replace with: "bro" and "dog"
</pre>
* You can also imitate Araida's random "ribbits" in between words:
<pre>
Regexp: "\s" Replace with: " ribbit ", " ", " ", " ", " ", " ", etc....
</pre>
where " " is just a blank space added a bunch of times. (You can see
how many blank spaces you've added by clicking on the list.) You have
to add the spaces because each entry has the same chance of being
selected. (Yes, I know this could be improved.) If you add " ribbit "
and 9 spaces, " ribbit " will have a 1/10 chance of being picked.
Also note that if you add more than one prefix or more than one
suffix, it will pick randomly from them instead of adding them both!
* <b>Mispeller</b>:
Be careful with thsi one. The mispeller will randomly mispell x% of
the words you type -- where x is the percentage you set the slider
to. I have attempted to mimic SBaHJ mispelling style but whoof knows
what will happen oh god ive created a mosnter
SMILIES
-------
Here's a list of smilies:
* :rancorous:
* :apple:
* :bathearst:
* :cathearst:
* :woeful:
* :pleasant:
* :blueghost:
* :slimer:
* :candycorn:
* :cheer:
* :duhjohn:
* :datrump:
* :facepalm:
* :bonk:
* :mspa:
* :gun:
* :cal:
* :amazedfirman:
* :amazed:
* :chummy:
* :cool:
* :smooth:
* :distraughtfirman
* :distraught:
* :insolent:
* :bemused:
* :3:
* :mystified:
* :pranky:
* :tense:
* :record:
* :squiddle:
* :tab:
* :beetip:
* :flipout:
* :befuddled:
* :pumpkin:
* :trollcool:
* :jadecry:
* :ecstatic:
* :relaxed:
* :discontent:
* :devious:
* :sleek:
* :detestful:
* :mirthful:
* :manipulative:
* :vigorous:
* :perky:
* :acceptant:

26
TODO
View file

@ -1,26 +0,0 @@
Bugs:
* weird memo time bug
* Windows doesn't show style sheet sometimes?? Maybe related to themes.
* Issues with connecting? Client not closing connection right? People keep getting "nick taken" messages
* Windows XP SP2: sometimes mouse clicks dont register? must be some kinda crash
* enamel doesnt have time arrows
Features:
* different sound for memos/pesters
* OOC
* log viewer needs to have BBCode/HTML/Text copy modes
* random pesters
* copy quirks between profiles?
* chum list groups
* More complex quirks: by-sound
* Theme checking
* Spy mode
* Animated
Mac Bugs:
* Mac doesn't show tabs right, display gifs, highlighting thing?
SS: also the background image is broken
SS: in the one-on-one pester it resizes with the window
SS: but the memo one doesn't resize
SS: and the arrows next to the time thing overlap the CLOSE button

40
TODO.mkdn Normal file
View file

@ -0,0 +1,40 @@
Todo
===============
Features
--------
* OOC
* log viewer needs to have BBCode/HTML/Text copy modes
* copy quirks between profiles?
* More complex quirks: by-sound
* Spy mode
* Turn @ and # links on/off?
* "someone has friended you" notifier
* Show true bans?
* Colour saving boxes things?
* Chum notes?
Bugs
----
* weird memo time bug
* Windows doesn't show style sheet sometimes?? Maybe related to themes.
* Issues with connecting? Client not closing connection right? People keep getting "nick taken" messages
* When using mood sort, scroll position jumps to last selected chum
* When left for a really long time, animations slow down pesterchum
* Openning userlist resets appearance of OP/voice for anyone that become OP/voice after you joined a memo
* If pesterchum is open but offline due to a network failure and you open the memos screen, it connects you but doesn't fetch the memo list when it finishes connecting
* right clicking an offline chum and choosing remove asks you why you're reporting someone, and if you hit cancel the menus stop working
* Closing a timeclone doesn't actually cease for everyone else
Windows Bugs
------------
* XP SP2: sometimes mouse clicks dont register? must be some kinda crash
* On reconnect and nick change, momentary theme change causes menu items to stop working
Mac Bugs
--------
* Mac doesn't show tabs right, display gifs, highlighting thing?
* SS: also the background image is broken
* SS: in the one-on-one pester it resizes with the window
* SS: but the memo one doesn't resize
* SS: and the arrows next to the time thing overlap the CLOSE button

74
bugreport.py Normal file
View file

@ -0,0 +1,74 @@
from PyQt4 import QtGui, QtCore
import urllib
import version
class BugReporter(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.mainwindow = parent
self.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"])
self.setWindowTitle("Report a Bug")
self.setModal(False)
self.title = QtGui.QLabel("Bug Report:")
layout_0 = QtGui.QVBoxLayout()
layout_0.addWidget(self.title)
layout_0.addWidget(QtGui.QLabel("Operating System (ex. Windows 7, Ubuntu 10.10):"))
self.os = QtGui.QLineEdit(self)
self.os.setStyleSheet("background:white; font-weight:bold; color:black; font-size: 10pt;")
layout_0.addWidget(self.os)
layout_0.addWidget(QtGui.QLabel("Description of bug:"))
descLabel = QtGui.QLabel("Include as much information as possible\n(theme, related options, what you were doing at the time, etc.)")
font = descLabel.font()
font.setPointSize(8)
descLabel.setFont(font)
layout_0.addWidget(descLabel)
self.textarea = QtGui.QTextEdit(self)
self.textarea.setStyleSheet("background:white; font-weight:normal; color:black; font-size: 10pt;")
layout_0.addWidget(self.textarea)
self.ok = QtGui.QPushButton("SEND", self)
self.ok.setDefault(True)
self.connect(self.ok, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('sendReport()'))
self.cancel = QtGui.QPushButton("CANCEL", self)
self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()'))
layout_2 = QtGui.QHBoxLayout()
layout_2.addWidget(self.cancel)
layout_2.addWidget(self.ok)
layout_0.addLayout(layout_2)
self.setLayout(layout_0)
@QtCore.pyqtSlot()
def sendReport(self):
name = unicode(self.mainwindow.profile().handle)
os = unicode(self.os.text())
msg = unicode(self.textarea.toPlainText())
if len(os) <= 0 or len(msg) <= 0:
msgbox = QtGui.QMessageBox()
msgbox.setStyleSheet(self.mainwindow.theme["main/defaultwindow/style"])
msgbox.setText("You must fill out all fields first!")
msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
ret = msgbox.exec_()
return
QtGui.QDialog.accept(self)
data = urllib.urlencode({"name":name, "version": version._pcVersion, "os":os, "msg":msg})
print "Sending..."
f = urllib.urlopen("http://distantsphere.com/pc/reporter.php", data)
text = f.read()
print text
if text == "success!":
print "Sent!"
else:
print "Problems ):"

129
convo.py
View file

@ -9,7 +9,7 @@ from PyQt4 import QtGui, QtCore
from dataobjs import PesterProfile, Mood, PesterHistory
from generic import PesterIcon
from parsetools import convertTags, lexMessage, splitMessage, mecmd, colorBegin, colorEnd, img2smiley
from parsetools import convertTags, lexMessage, splitMessage, mecmd, colorBegin, colorEnd, img2smiley, smiledict
class PesterTabWindow(QtGui.QFrame):
def __init__(self, mainwindow, parent=None, convo="convo"):
@ -19,11 +19,14 @@ class PesterTabWindow(QtGui.QFrame):
self.mainwindow = mainwindow
self.tabs = QtGui.QTabBar(self)
self.tabs.setMovable(True)
self.tabs.setTabsClosable(True)
self.connect(self.tabs, QtCore.SIGNAL('currentChanged(int)'),
self, QtCore.SLOT('changeTab(int)'))
self.connect(self.tabs, QtCore.SIGNAL('tabCloseRequested(int)'),
self, QtCore.SLOT('tabClose(int)'))
self.connect(self.tabs, QtCore.SIGNAL('tabMoved(int, int)'),
self, QtCore.SLOT('tabMoved(int, int)'))
self.initTheme(self.mainwindow.theme)
self.layout = QtGui.QVBoxLayout()
@ -194,17 +197,77 @@ class PesterTabWindow(QtGui.QFrame):
self.raise_()
convo.raiseChat()
@QtCore.pyqtSlot(int, int)
def tabMoved(self, to, fr):
l = self.tabIndices
for i in l:
if l[i] == fr:
oldpos = i
if l[i] == to:
newpos = i
l[oldpos] = to
l[newpos] = fr
windowClosed = QtCore.pyqtSignal()
class PesterText(QtGui.QTextEdit):
def __init__(self, theme, parent=None):
QtGui.QTextEdit.__init__(self, parent)
if hasattr(self.parent(), 'mainwindow'):
self.mainwindow = self.parent().mainwindow
else:
self.mainwindow = self.parent()
self.initTheme(theme)
self.setReadOnly(True)
self.setMouseTracking(True)
self.textSelected = False
self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'),
self, QtCore.SLOT('textReady(bool)'))
self.urls = {}
for k in smiledict:
self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k]))
self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'),
self, QtCore.SLOT('animateChanged(bool)'))
def addAnimation(self, url, fileName):
movie = QtGui.QMovie(self)
movie.setFileName(fileName)
if movie.frameCount() > 1:
self.urls[movie] = url
self.connect(movie, QtCore.SIGNAL('frameChanged(int)'),
self, QtCore.SLOT('animate(int)'))
#movie.start()
@QtCore.pyqtSlot(int)
def animate(self, frame):
if self.mainwindow.config.animations():
movie = self.sender()
url = self.urls[movie].toString()
html = unicode(self.toHtml())
if html.find(url) != -1:
if self.parent().parent():
i = self.parent().parent().tabIndices[self.parent().title()]
if self.parent().parent().tabs.currentIndex() == i:
self.document().addResource(QtGui.QTextDocument.ImageResource,
self.urls[movie], movie.currentPixmap())
self.setLineWrapColumnOrWidth(self.lineWrapColumnOrWidth())
else:
self.document().addResource(QtGui.QTextDocument.ImageResource,
self.urls[movie], movie.currentPixmap())
self.setLineWrapColumnOrWidth(self.lineWrapColumnOrWidth())
@QtCore.pyqtSlot(bool)
def animateChanged(self, animate):
if animate:
for m in self.urls:
html = unicode(self.toHtml())
if html.find(self.urls[m].toString()) != -1:
if m.frameCount() > 1:
m.start()
else:
for m in self.urls:
html = unicode(self.toHtml())
if html.find(self.urls[m].toString()) != -1:
if m.frameCount() > 1:
m.stop()
@QtCore.pyqtSlot(bool)
def textReady(self, ready):
self.textSelected = ready
@ -222,6 +285,11 @@ class PesterText(QtGui.QTextEdit):
parent = self.parent()
window = parent.mainwindow
me = window.profile()
if self.mainwindow.config.animations():
for m in self.urls:
if convertTags(lexmsg).find(self.urls[m].toString()) != -1:
if m.state() == QtGui.QMovie.NotRunning:
m.start()
if self.parent().mainwindow.config.showTimeStamps():
if self.parent().mainwindow.config.time12Format():
time = strftime("[%I:%M")
@ -276,7 +344,7 @@ class PesterText(QtGui.QTextEdit):
lexmsg[0:0] = [colorBegin("<c=%s>" % (color), color),
"%s: " % (initials)]
lexmsg.append(colorEnd("</c>"))
self.append(time + convertTags(lexmsg))
self.append("<span style=\"color:#000000\">" + time + convertTags(lexmsg) + "</span>")
if chum is me:
window.chatlog.log(parent.chum.handle, lexmsg)
else:
@ -299,16 +367,27 @@ class PesterText(QtGui.QTextEdit):
self.parent().clearNewMessage()
QtGui.QTextEdit.focusInEvent(self, event)
def keyPressEvent(self, event):
if hasattr(self.parent(), 'textInput'):
if event.key() not in [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, \
QtCore.Qt.Key_Up, QtCore.Qt.Key_Down]:
self.parent().textInput.keyPressEvent(event)
QtGui.QTextEdit.keyPressEvent(self, event)
def mousePressEvent(self, event):
url = self.anchorAt(event.pos())
if url != "":
if url[0] == "#" and url != "#pesterchum":
self.parent().mainwindow.showMemos(url[1:])
elif url[0] == "@":
handle = unicode(url[1:])
self.parent().mainwindow.newConversation(handle)
else:
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
if event.button() == QtCore.Qt.LeftButton:
url = self.anchorAt(event.pos())
if url != "":
if url[0] == "#" and url != "#pesterchum":
self.parent().mainwindow.showMemos(url[1:])
elif url[0] == "@":
handle = unicode(url[1:])
self.parent().mainwindow.newConversation(handle)
else:
if event.modifiers() == QtCore.Qt.ControlModifier:
QtGui.QApplication.clipboard().setText(url)
else:
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
QtGui.QTextEdit.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
QtGui.QTextEdit.mouseMoveEvent(self, event)
@ -449,8 +528,12 @@ class PesterConvo(QtGui.QFrame):
self.reportchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/report"], self)
self.connect(self.reportchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('reportThisChum()'))
self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
self.connect(self.logchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('openChumLogs()'))
self.optionsMenu.addAction(self.quirksOff)
self.optionsMenu.addAction(self.logchum)
self.optionsMenu.addAction(self.addChumAction)
self.optionsMenu.addAction(self.blockAction)
self.optionsMenu.addAction(self.reportchum)
@ -533,6 +616,7 @@ class PesterConvo(QtGui.QFrame):
# ok if it has a tabconvo parent, send that the notify.
if self.parent():
self.parent().notifyNewMessage(self.title())
self.mainwindow.gainAttention.emit(self.parent())
# if not change the window title and update system tray
else:
self.newmessage = True
@ -540,6 +624,7 @@ class PesterConvo(QtGui.QFrame):
def func():
self.showChat()
self.mainwindow.waitingMessages.addMessage(self.title(), func)
self.mainwindow.gainAttention.emit(self)
def clearNewMessage(self):
if self.parent():
@ -591,6 +676,7 @@ class PesterConvo(QtGui.QFrame):
self.addChumAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/addchum"])
self.blockAction.setText(self.mainwindow.theme["main/menus/rclickchumlist/blockchum"])
self.unblockchum.setText(self.mainwindow.theme["main/menus/rclickchumlist/unblockchum"])
self.logchum.setText(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"])
self.textArea.changeTheme(theme)
self.textInput.changeTheme(theme)
@ -605,7 +691,14 @@ class PesterConvo(QtGui.QFrame):
quirks = self.mainwindow.userprofile.quirks
lexmsg = lexMessage(text)
if type(lexmsg[0]) is not mecmd and self.applyquirks:
lexmsg = quirks.apply(lexmsg)
try:
lexmsg = quirks.apply(lexmsg)
except:
msgbox = QtGui.QMessageBox()
msgbox.setText("Whoa there! There seems to be a problem.")
msgbox.setInformativeText("A quirk seems to be having a problem. (Possibly you're trying to capture a non-existant group?)")
msgbox.exec_()
return
lexmsgs = splitMessage(lexmsg)
for lm in lexmsgs:
@ -634,6 +727,15 @@ class PesterConvo(QtGui.QFrame):
@QtCore.pyqtSlot(bool)
def toggleQuirks(self, toggled):
self.applyquirks = not toggled
@QtCore.pyqtSlot()
def openChumLogs(self):
currentChum = self.chum.handle
self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow)
self.connect(self.mainwindow.chumList.pesterlogviewer, QtCore.SIGNAL('rejected()'),
self.mainwindow.chumList, QtCore.SLOT('closeActiveLog()'))
self.mainwindow.chumList.pesterlogviewer.show()
self.mainwindow.chumList.pesterlogviewer.raise_()
self.mainwindow.chumList.pesterlogviewer.activateWindow()
messageSent = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
windowClosed = QtCore.pyqtSignal(QtCore.QString)
@ -644,3 +746,6 @@ class PesterConvo(QtGui.QFrame):
"v": {"center": QtCore.Qt.AlignVCenter,
"top": QtCore.Qt.AlignTop,
"bottom": QtCore.Qt.AlignBottom } }
# the import is way down here to avoid recursive imports
from logviewer import PesterLogViewer

View file

@ -49,8 +49,16 @@ class pesterQuirk(object):
raise ValueError("Quirks must be given a dictionary")
self.quirk = quirk
self.type = self.quirk["type"]
if "on" not in self.quirk:
self.quirk["on"] = True
self.on = self.quirk["on"]
if "group" not in self.quirk:
self.quirk["group"] = "Miscellaneous"
self.group = self.quirk["group"]
def apply(self, string, first=False, last=False):
if self.type == "prefix":
if not self.on:
return string
elif self.type == "prefix":
return self.quirk["value"] + string
elif self.type == "suffix":
return string + self.quirk["value"]
@ -119,10 +127,6 @@ class pesterQuirks(object):
def apply(self, lexed, first=False, last=False):
prefix = [q for q in self.quirklist if q.type=='prefix']
suffix = [q for q in self.quirklist if q.type=='suffix']
replace = [q for q in self.quirklist if
q.type=='replace' or q.type=='regexp']
randomrep = [q for q in self.quirklist if q.type=='random']
spelling = [q for q in self.quirklist if q.type=='spelling']
newlist = []
for (i, o) in enumerate(lexed):
@ -136,20 +140,16 @@ class pesterQuirks(object):
continue
lastStr = (i == len(lexed)-1)
string = o
for s in spelling:
string = s.apply(string)
for r in randomrep:
string = r.apply(string, first=(i==0), last=lastStr)
for r in replace:
string = r.apply(string, first=(i==0), last=lastStr)
if i == 0:
if len(prefix) >= 1:
myprefix = random.choice(prefix)
string = myprefix.apply(string)
if lastStr:
if len(suffix) >= 1:
mysuffix = random.choice(suffix)
string = mysuffix.apply(string)
for q in self.quirklist:
if q.type != 'prefix' and q.type != 'suffix':
if q.type == 'regexp' or q.type == 'random':
string = q.apply(string, first=(i==0), last=lastStr)
else:
string = q.apply(string)
elif q.type == 'prefix' and i == 0:
string = q.apply(string)
elif q.type == 'suffix' and lastStr:
string = q.apply(string)
newlist.append(string)
final = []
@ -165,7 +165,7 @@ class pesterQuirks(object):
yield q
class PesterProfile(object):
def __init__(self, handle, color=None, mood=Mood("offline"), chumdb=None):
def __init__(self, handle, color=None, mood=Mood("offline"), group=None, chumdb=None):
self.handle = handle
if color is None:
if chumdb:
@ -174,6 +174,12 @@ class PesterProfile(object):
color = QtGui.QColor("black")
self.color = color
self.mood = mood
if group is None:
if chumdb:
group = chumdb.getGroup(handle, "Chums")
else:
group = "Chums"
self.group = group
def initials(self, time=None):
handle = self.handle
caps = [l for l in handle if l.isupper()]
@ -203,7 +209,8 @@ class PesterProfile(object):
def plaindict(self):
return (self.handle, {"handle": self.handle,
"mood": self.mood.name(),
"color": unicode(self.color.name())})
"color": unicode(self.color.name()),
"group": unicode(self.group)})
def blocked(self, config):
return self.handle in config.getBlocklist()
@ -223,7 +230,7 @@ class PesterProfile(object):
def moodmsg(self, mood, syscolor, theme):
return "<c=%s>-- %s <c=%s>[%s]</c> changed their mood to %s <img src='%s' /> --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), mood.name().upper(), theme["main/chums/moods"][mood.name()]["icon"])
def idlemsg(self, syscolor, verb):
return "<c=%s>-- %s <c=%s>[%s]</c> %s --" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb)
return "<c=%s>-- %s <c=%s>[%s]</c> %s --</c>" % (syscolor.name(), self.handle, self.colorhtml(), self.initials(), verb)
def memoclosemsg(self, syscolor, timeGrammar, verb):
return "<c=%s><c=%s>%s%s%s</c> %s.</c>" % (syscolor.name(), self.colorhtml(), timeGrammar.pcf, self.initials(), timeGrammar.number, verb)
def memoopenmsg(self, syscolor, td, timeGrammar, verb, channel):
@ -232,18 +239,38 @@ class PesterProfile(object):
initials = pcf+self.initials()
return "<c=%s><c=%s>%s</c> %s %s %s.</c>" % \
(syscolor.name(), self.colorhtml(), initials, timetext, verb, channel[1:].upper().replace("_", " "))
def memobanmsg(self, opchum, opgrammar, syscolor, timeGrammar):
def memobanmsg(self, opchum, opgrammar, syscolor, timeGrammar, reason):
initials = timeGrammar.pcf+self.initials()+timeGrammar.number
opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo." % \
(opchum.colorhtml(), opinit, self.colorhtml(), initials)
if opchum.handle == reason:
return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo." % \
(opchum.colorhtml(), opinit, self.colorhtml(), initials)
else:
return "<c=%s>%s</c> banned <c=%s>%s</c> from responding to memo: <c=black>[%s]</c>." % \
(opchum.colorhtml(), opinit, self.colorhtml(), initials, unicode(reason))
def memojoinmsg(self, syscolor, td, timeGrammar, verb):
(temporal, pcf, when) = (timeGrammar.temporal, timeGrammar.pcf, timeGrammar.when)
timetext = timeDifference(td)
initials = pcf+self.initials()+timeGrammar.number
return "<c=%s><c=%s>%s %s [%s]</c> %s %s." % \
return "<c=%s><c=%s>%s %s [%s]</c> %s %s.</c>" % \
(syscolor.name(), self.colorhtml(), temporal, self.handle,
initials, timetext, verb)
def memoopmsg(self, opchum, opgrammar, syscolor):
opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
return "<c=%s>%s</c> made <c=%s>%s</c> an OP." % \
(opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
def memodeopmsg(self, opchum, opgrammar, syscolor):
opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
return "<c=%s>%s</c> took away <c=%s>%s</c>'s OP powers." % \
(opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
def memovoicemsg(self, opchum, opgrammar, syscolor):
opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
return "<c=%s>%s</c> gave <c=%s>%s</c> voice." % \
(opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
def memodevoicemsg(self, opchum, opgrammar, syscolor):
opinit = opgrammar.pcf+opchum.initials()+opgrammar.number
return "<c=%s>%s</c> took away <c=%s>%s</c>'s voice." % \
(opchum.colorhtml(), opinit, self.colorhtml(), self.initials())
@staticmethod
def checkLength(handle):

283
easyInstaller Executable file
View file

@ -0,0 +1,283 @@
#!/usr/bin/env python
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
import sys, traceback
error = 0
try:
import os, shutil
from stat import *
from string import Template
_PLATFORM = sys.platform
if _PLATFORM in ['win32','cygwin','darwin','os2','os2emx','riscos','atheos']:
print "Whoa there buddy! This installation script isn't meant to be run on your OS."
exit()
if os.getuid() != 0:
print "This program must be run as root (sudo)."
exit()
_HOME = os.environ['HOME']
_USER = os.environ['SUDO_USER']
_UID = int(os.environ['SUDO_UID'])
_GID = int(os.environ['SUDO_GID'])
# fix home if it's root weirdness
if _HOME.find("root") != -1:
_HOME = "/home/"+_USER
def setPermissions(path):
os.chown(path, _UID, _GID)
for file_ in os.listdir(path):
filePath = os.path.join(path,file_)
if os.path.isdir(filePath):
setPermissions(filePath)
else:
os.chown(filePath, _UID, _GID)
def findPesterchum(path):
for f in os.listdir(path):
filePath = os.path.join(path, f)
if os.path.isdir(filePath):
if os.path.exists(filePath+"/pesterchum.py"):
return filePath
else:
a=findPesterchum(filePath)
if a: return a
elif f == "pesterchum.py":
return path
if not os.path.exists(_HOME+"/.pcInstallLoc"):
print "Welcome to the Pesterchum 3.14 Easy Installer (for Linux)!\n\
Created by Kiooeht [evacipatedBox] May 28th-29th, 2011.\n\
License: WTFPL\n\
\n\
Leaving an option blank will accept it's default [in brackets]\n\
Are you ready to begin your MAGICAL JOURNEY?!\n\
Of course you are!!! ::::D"
# ask user about things
while 1:
install = raw_input("Install location [~/.pesterchum]: ")
if install == "":
instLoc = _HOME+"/.pesterchum"
break
else:
if install[0] == "~":
install = _HOME+install[1:]
if os.path.exists(install[:install.rfind("/")]):
instLoc = install
break
print "No can do"
if os.path.exists("/usr/share/applications"):
while 1:
gnome = raw_input("Create a GNOME menu item? [Y/n]: ")
if gnome.lower() == "y" or gnome == "":
gnome = True;break
elif gnome.lower() == "n":
gnome = False;break
else:
print "herpaderp"
while 1:
shortcut = raw_input("Create launcher in home directory? [Y/n]: ")
if shortcut.lower() == "y" or shortcut == "":
shortcut = True;break
elif shortcut.lower() == "n":
shortcut = False;break
else:
print "u jelly?"
# do some shitty install
try:
fileLoc = findPesterchum(".")
except RuntimeError:
print "I'm sorry! I was unable to find the pesterchum files :("
print "Please put them where I can find them"
exit()
if not fileLoc:
print "I'm sorry! I was unable to find the pesterchum files :("
print "Please put them where I can find them"
exit()
print "Copying files..."
ignore = shutil.ignore_patterns('*.pyc')
if not os.path.exists(instLoc):
shutil.copytree(fileLoc, instLoc, ignore=ignore)
if os.path.exists(instLoc+"/pesterchum.js"):
f = open(instLoc+"/pesterchum.js")
js = f.read()
f.close()
defa = js.find("\"defaultprofile\"")
if defa != -1:
start = js.find("\"", js.find(":", defa+1))
end = js.find("\"", start+1)
party = js[start+1:end]
if not os.path.exists(instLoc+"/profiles") or \
party+".js" not in os.listdir(instLoc+"/profiles"):
print "Protecting you from stupidity..."
print " (aka. Deleting reference to non-existant default profile)"
#os.remove(instLoc+"/pesterchum.js")
f = open(instLoc+"/pesterchum.js", "w")
f.write(js[:defa-1]+js[js.find(",", end)+1:])
f.close()
else:
if not os.path.exists(instLoc+"/logs") and os.path.exists(fileLoc+"/logs"):
shutil.copytree(fileLoc+"/logs", instLoc+"/logs", ignore=ignore)
if not os.path.exists(instLoc+"/profiles") and os.path.exists(fileLoc+"/profiles"):
shutil.copytree(fileLoc+"/profiles", instLoc+"/profiles", ignore=ignore)
if not os.path.exists(instLoc+"/pesterchum.js") and os.path.exists(fileLoc+"/pesterchum.js"):
shutil.copy(fileLoc+"/pesterchum.js", instLoc)
shutil.copytree(fileLoc+"/oyoyo", instLoc+"/oyoyo", ignore=ignore)
shutil.copytree(fileLoc+"/smilies", instLoc+"/smilies", ignore=ignore)
shutil.copytree(fileLoc+"/themes", instLoc+"/themes", ignore=ignore)
for f in os.listdir(fileLoc):
filePath = os.path.join(fileLoc, f)
if not os.path.isdir(filePath) and f != "pesterchum.js":
shutil.copy(filePath, instLoc)
setPermissions(instLoc)
# save the install location
f = open(_HOME+"/.pcInstallLoc", "w")
f.write(instLoc)
f.close()
#create a cool executable
print "Creating executable... (/usr/local/bin/pesterchum)"
f = open("/usr/local/bin/pesterchum", 'w')
f.write("#!/bin/sh\ncd "+instLoc+"\n./pesterchum $@")
f.close()
os.chmod("/usr/local/bin/pesterchum", S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
# Create a fancy menu item in gnome
if gnome:
print "Creating menu item..."
t = Template("[Desktop Entry]\nEncoding=UTF-8\nVersion=3.14.2\nName=Pesterchum\nComment=IM client based on Homestuck Pesterchum\nCategories=Network;InstantMessaging;\nExec=/usr/local/bin/pesterchum\nIcon=$loc/pesterchum.ico\nTerminal=false\nType=Application")
f = open("/usr/share/applications/pesterchum.desktop", "w")
f.write(t.safe_substitute(loc=instLoc))
f.close()
# create shortcut launcher
if shortcut:
print "Creating launcher..."
t = Template("#!/usr/bin/env xdg-open\n[Desktop Entry]\nEncoding=UTF-8\nVersion=3.14.2\nName=Pesterchum\nComment=IM client based on Homestuck Pesterchum\nCategories=Network;InstantMessaging;\nExec=pesterchum\nIcon=$loc/pesterchum.ico\nTerminal=false\nType=Application")
f = open(_HOME+"/Pesterchum.desktop", "w")
f.write(t.safe_substitute(loc=instLoc))
f.close()
os.chown(_HOME+"/Pesterchum.desktop", _UID, _GID)
os.chmod(_HOME+"/Pesterchum.desktop", S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
else:
print "Welcome to the Pesterchum 3.14 Easy Uninstaller (for Linux)!\n\
Created by Kiooeht [evacipatedBox] May 28th-29th, 2011.\n\
License: WTFPL\n"
while 1:
remove = raw_input("Would you like to uninstall Pesterchum? [y/n]: ")
if remove.lower() == "y":
while 1:
killdata = raw_input("Purge your settings, profiles, and logs? [y/N]: ")
if killdata.lower() == "n" or killdata == "":
killdata = False;break
elif killdata.lower() == "y":
killdata = True;break
else:
print "Hmmmmm...?"
f = open(_HOME+"/.pcInstallLoc")
instLoc = f.readline()
f.close()
os.remove(_HOME+"/.pcInstallLoc")
if killdata:
print "Removing files..."
shutil.rmtree(instLoc)
else:
print "Backing up settings, profiles, and logs..."
if os.path.exists(instLoc+"/logs"):
shutil.move(instLoc+"/logs", "_easyBackupLOGS")
if os.path.exists(instLoc+"/profiles"):
shutil.move(instLoc+"/profiles", "_easyBackupPROFILES")
if os.path.exists(instLoc+"/pesterchum.js"):
shutil.move(instLoc+"/pesterchum.js", "_easyBackupSETTINGS")
print "Removing files..."
shutil.rmtree(instLoc)
print "Restoring up settings, profiles, and logs..."
os.mkdir(instLoc)
if os.path.exists("_easyBackupLOGS"):
shutil.move("_easyBackupLOGS", instLoc+"/logs")
if os.path.exists("_easyBackupPROFILES"):
shutil.move("_easyBackupPROFILES", instLoc+"/profiles")
if os.path.exists("_easyBackupSETTINGS"):
shutil.move("_easyBackupSETTINGS", instLoc+"/pesterchum.js")
setPermissions(instLoc)
print "Trashing executable..."
os.remove("/usr/local/bin/pesterchum")
if os.path.exists("/usr/share/applications/pesterchum.desktop"):
print "Maiming menu item..."
os.remove("/usr/share/applications/pesterchum.desktop")
if os.path.exists(_HOME+"/Pesterchum.desktop"):
print "Destroying launcher..."
os.remove(_HOME+"/Pesterchum.desktop")
elif os.path.exists(_HOME+"/Desktop/Pesterchum.desktop"):
print "Destroying launcher..."
os.remove(_HOME+"/Desktop/Pesterchum.desktop")
else:
print "Unable to find launcher, non destroyed"
break
elif remove.lower() == "n":
print "Aborting uninstallation process"
break
else:
print "Invalid input, try again"
except KeyboardInterrupt:
print ""
except Exception, e:
error = -1
finally:
if error == -1:
print "Oh noes!! It seems an error has occurred!"
lineN = traceback.extract_tb(sys.exc_info()[2])[-1][1]
print "The error occurred on line %s:" % lineN
formatted_lines = traceback.format_exc().splitlines()
print " '" + formatted_lines[-2] + "'"
print formatted_lines[-1]
while 1:
print "\nWould you like to (s)end a bug report,"
send = raw_input("view the (f)ull error message, or (n)either? [s/f/n]: ")
if send.lower() == "n":
act = 2;break
elif send.lower() == "s":
act = 0;break
elif send.lower() == "f":
print "!---------------BEGIN ERROR MESSAGE---------------!"
for l in formatted_lines:
print l
print "!----------------END ERROR MESSAGE----------------!"
send = raw_input("Would you like to send this error message? [y/n]: ")
if send.lower() == "y":
act = 0;break
elif send.lower() == "n":
act = 2;break
else:
print "What was that?"
if act == 2:
print "Okay"
elif act == 0:
print "Thank you for taking time out of your day to complete a bug report."
print "Fields marked with an asterisk (*) are required."
name = raw_input("Your Name: ")
while 1:
os = raw_input("OS (include version) (ex. Ubuntu 10.10) [*]: ")
if os: break
else: print "This field is required."
while 1:
msg = raw_input("Short description of problem [*]: ")
if msg: break
else: print "This field is required."
import urllib, json
data = urllib.urlencode({"name":name, "os":os, "msg":msg, "short":formatted_lines[-1], "long":json.dumps(formatted_lines)})
try:
print "Sending..."
f = urllib.urlopen("http://distantsphere.com/pc/easyInstall.php", data)
text = f.read()
print text
if text == "success!":
print "Sent!"
else:
print "There seems to have been a problem sending your bug report! ):"
except:
print "There seems to have been a problem sending your bug report! ):"

2858
feedparser.py Executable file

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@ class PesterList(list):
class PesterIcon(QtGui.QIcon):
def __init__(self, *x, **y):
QtGui.QIcon.__init__(self, *x, **y)
QtGui.QIcon.__init__(self, x[0])
if type(x[0]) in [str, unicode]:
self.icon_pixmap = QtGui.QPixmap(x[0])
else:
@ -50,6 +50,15 @@ class RightClickList(QtGui.QListWidget):
def getOptionsMenu(self):
return self.optionsMenu
class RightClickTree(QtGui.QTreeWidget):
def contextMenuEvent(self, event):
if event.reason() == QtGui.QContextMenuEvent.Mouse:
listing = self.itemAt(event.pos())
self.setCurrentItem(listing)
self.getOptionsMenu().popup(event.globalPos())
def getOptionsMenu(self):
return self.optionsMenu
class MultiTextDialog(QtGui.QDialog):
def __init__(self, title, parent, *queries):
QtGui.QDialog.__init__(self, parent)

167
irc.py
View file

@ -5,9 +5,11 @@ from oyoyo import helpers
import logging
import random
import socket
from time import time
from dataobjs import Mood, PesterProfile
from generic import PesterList
from version import _pcVersion
logging.basicConfig(level=logging.INFO)
@ -53,7 +55,7 @@ class PesterIRC(QtCore.QThread):
if not res:
logging.debug("false Yield: %s, returning" % res)
return
def setConnected(self):
self.registeredIRC = True
self.connected.emit()
@ -87,18 +89,49 @@ class PesterIRC(QtCore.QThread):
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(PesterList)
def getMoods(self, chums):
self.cli.command_handler.getMood(*chums)
self.cli.command_handler.getMood(*chums)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def sendNotice(self, text, handle):
h = unicode(handle)
t = unicode(text)
try:
helpers.notice(self.cli, h, t)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def sendMessage(self, text, handle):
h = unicode(handle)
textl = [unicode(text)]
def splittext(l):
if len(l[0]) > 450:
space = l[0].rfind(" ", 0,450)
space = l[0].rfind(" ", 0,430)
if space == -1:
space = 450
elif l[0][space+1:space+5] == "</c>":
space = space+4
a = l[0][0:space+1]
b = l[0][space+1:]
if a.count("<c") > a.count("</c>"):
# oh god ctags will break!! D=
hanging = []
usedends = []
c = a.rfind("<c")
while c != -1:
d = a.find("</c>", c)
while d in usedends:
d = a.find("</c>", d+1)
if d != -1: usedends.append(d)
else:
f = a.find(">", c)+1
hanging.append(a[c:f])
c = a.rfind("<c",0,c)
# end all ctags in first part
for i in range(a.count("<c")-a.count("</c>")):
a = a + "</c>"
#start them up again in the second part
for c in hanging:
b = c + b
if len(b) > 0:
return [a] + splittext([b])
else:
@ -135,6 +168,7 @@ class PesterIRC(QtCore.QThread):
helpers.nick(self.cli, handle)
except socket.error:
self.setConnectionBroken()
self.mainwindow.closeConversations(True)
self.updateMood()
@QtCore.pyqtSlot()
def updateMood(self):
@ -183,6 +217,7 @@ class PesterIRC(QtCore.QThread):
c = unicode(channel)
try:
helpers.join(self.cli, c)
helpers.mode(self.cli, c, "", None)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString)
@ -194,10 +229,15 @@ class PesterIRC(QtCore.QThread):
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def kickUser(self, handle, channel):
l = handle.split(":")
c = unicode(channel)
h = unicode(handle)
h = unicode(l[0])
if len(l) > 1:
reason = unicode(l[1])
else:
reason = ""
try:
helpers.kick(self.cli, h, c)
helpers.kick(self.cli, h, c, reason)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
@ -211,21 +251,60 @@ class PesterIRC(QtCore.QThread):
helpers.mode(self.cli, c, m, cmd)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString)
def channelNames(self, channel):
c = unicode(channel)
try:
helpers.names(self.cli, c)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def inviteChum(self, handle, channel):
h = unicode(handle)
c = unicode(channel)
try:
helpers.invite(self.cli, h, c)
except socket.error:
self.setConnectionBroken()
@QtCore.pyqtSlot()
def pingServer(self):
try:
self.cli.send("PING %s" % int(time()))
except socket.error:
self.setConnectionBroken()
moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood)
colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
memoReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
noticeReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
inviteReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
timeCommand = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList)
channelListReceived = QtCore.pyqtSignal(PesterList)
nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
myHandleChanged = QtCore.pyqtSignal(QtCore.QString)
chanInviteOnly = QtCore.pyqtSignal(QtCore.QString)
modesUpdated = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
connected = QtCore.pyqtSignal()
userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString,
QtCore.QString)
cannotSendToChan = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
tooManyPeeps = QtCore.pyqtSignal()
class PesterHandler(DefaultCommandHandler):
def notice(self, nick, chan, msg):
try:
msg = msg.decode('utf-8')
except UnicodeDecodeError:
msg = msg.decode('iso-8859-1', 'ignore')
handle = nick[0:nick.find("!")]
logging.info("---> recv \"NOTICE %s :%s\"" % (handle, msg))
if handle == "ChanServ" and chan == self.parent.mainwindow.profile().handle and msg[0:2] == "[#":
self.parent.memoReceived.emit(msg[1:msg.index("]")], handle, msg)
else:
self.parent.noticeReceived.emit(handle, msg)
def privmsg(self, nick, chan, msg):
try:
msg = msg.decode('utf-8')
@ -236,6 +315,10 @@ class PesterHandler(DefaultCommandHandler):
return
# silently ignore CTCP
if msg[0] == '\x01':
handle = nick[0:nick.find("!")]
logging.info("---> recv \"CTCP %s :%s\"" % (handle, msg[1:-1]))
if msg[1:-1] == "VERSION":
helpers.notice(self.parent.cli, handle, "\x01VERSION Pesterchum %s\x01" % (_pcVersion))
return
handle = nick[0:nick.find("!")]
logging.info("---> recv \"PRIVMSG %s :%s\"" % (handle, msg))
@ -251,7 +334,7 @@ class PesterHandler(DefaultCommandHandler):
mychumhandle = self.mainwindow.profile().handle
mymood = self.mainwindow.profile().mood.value()
if msg.find(mychumhandle, 8) != -1:
helpers.msg(self.client, "#pesterchum",
helpers.msg(self.client, "#pesterchum",
"MOOD >%d" % (mymood))
elif chan[0] == '#':
if msg[0:16] == "PESTERCHUM:TIME>":
@ -282,9 +365,6 @@ class PesterHandler(DefaultCommandHandler):
mymood = self.mainwindow.profile().mood.value()
helpers.msg(self.client, "#pesterchum", "MOOD >%d" % (mymood))
chums = self.mainwindow.chumList.chums
self.getMood(*chums)
def nicknameinuse(self, server, cmd, nick, msg):
newnick = "pesterClient%d" % (random.randint(100,999))
helpers.nick(self.client, newnick)
@ -293,8 +373,9 @@ class PesterHandler(DefaultCommandHandler):
handle = nick[0:nick.find("!")]
self.parent.userPresentUpdate.emit(handle, "", "quit")
self.parent.moodUpdated.emit(handle, Mood("offline"))
def kick(self, opnick, channel, handle, op):
self.parent.userPresentUpdate.emit(handle, channel, "kick:%s" % (op))
def kick(self, opnick, channel, handle, reason):
op = opnick[0:opnick.find("!")]
self.parent.userPresentUpdate.emit(handle, channel, "kick:%s:%s" % (op, reason))
# ok i shouldnt be overloading that but am lazy
def part(self, nick, channel, reason="nanchos"):
handle = nick[0:nick.find("!")]
@ -306,8 +387,35 @@ class PesterHandler(DefaultCommandHandler):
self.parent.userPresentUpdate.emit(handle, channel, "join")
if channel == "#pesterchum":
self.parent.moodUpdated.emit(handle, Mood("chummy"))
def mode(self, op, channel, mode, handle=""):
self.parent.userPresentUpdate.emit(handle, channel, mode)
def mode(self, op, channel, mode, *handles):
if len(handles) <= 0: handles = [""]
opnick = op[0:op.find("!")]
if op == channel or channel == self.parent.mainwindow.profile().handle:
modes = list(self.parent.mainwindow.modes)
if modes and modes[0] == "+": modes = modes[1:]
if mode[0] == "+":
for m in mode[1:]:
if m not in modes:
modes.extend(m)
elif mode[0] == "-":
for i in mode[1:]:
try:
modes.remove(i)
except ValueError:
pass
modes.sort()
self.parent.mainwindow.modes = "+" + "".join(modes)
modes = []
cur = "+"
for l in mode:
if l in ["+","-"]: cur = l
else:
modes.append("%s%s" % (cur, l))
for (i,m) in enumerate(modes):
try:
self.parent.userPresentUpdate.emit(handles[i], channel, m+":%s" % (op))
except IndexError:
self.parent.userPresentUpdate.emit("", channel, m+":%s" % (op))
def nick(self, oldnick, newnick):
oldhandle = oldnick[0:oldnick.find("!")]
if oldhandle == self.mainwindow.profile().handle:
@ -322,7 +430,7 @@ class PesterHandler(DefaultCommandHandler):
logging.info("---> recv \"NAMES %s: %d names\"" % (channel, len(namelist)))
if not hasattr(self, 'channelnames'):
self.channelnames = {}
if not self.channelnames.has_key(channel):
if channel not in self.channelnames:
self.channelnames[channel] = []
self.channelnames[channel].extend(namelist)
def endofnames(self, server, nick, channel, msg):
@ -330,6 +438,15 @@ class PesterHandler(DefaultCommandHandler):
pl = PesterList(namelist)
del self.channelnames[channel]
self.parent.namesReceived.emit(channel, pl)
if channel == "#pesterchum" and not hasattr(self, "joined"):
self.joined = True
chums = self.mainwindow.chumList.chums
lesschums = []
for c in chums:
chandle = c.handle
if chandle in namelist:
lesschums.append(c)
self.getMood(*lesschums)
def liststart(self, server, handle, *info):
self.channel_list = []
@ -347,7 +464,25 @@ class PesterHandler(DefaultCommandHandler):
logging.info("---> recv \"CHANNELS END\"")
self.parent.channelListReceived.emit(pl)
self.channel_list = []
def umodeis(self, server, handle, modes):
self.parent.mainwindow.modes = modes
def invite(self, sender, you, channel):
handle = sender.split('!')[0]
self.parent.inviteReceived.emit(handle, channel)
def inviteonlychan(self, server, handle, channel, msg):
self.parent.chanInviteOnly.emit(channel)
def channelmodeis(self, server, handle, channel, modes):
self.parent.modesUpdated.emit(channel, modes)
def cannotsendtochan(self, server, handle, channel, msg):
self.parent.cannotSendToChan.emit(channel, msg)
def toomanypeeps(self, *stuff):
self.parent.tooManyPeeps.emit()
def ping(self, prefix, server):
self.parent.mainwindow.lastping = int(time())
self.client.send('PONG', server)
def getMood(self, *chums):
chumglub = "GETMOOD "
for c in chums:
@ -364,4 +499,4 @@ class PesterHandler(DefaultCommandHandler):
helpers.msg(self.client, "#pesterchum", chumglub)
except socket.error:
self.parent.setConnectionBroken()

View file

@ -3,10 +3,36 @@ import codecs
import re
from time import strftime, strptime
from PyQt4 import QtGui, QtCore
from generic import RightClickList
from generic import RightClickList, RightClickTree
from parsetools import convertTags
from convo import PesterText
class PesterLogSearchInput(QtGui.QLineEdit):
def __init__(self, theme, parent=None):
QtGui.QLineEdit.__init__(self, parent)
self.setStyleSheet(theme["convo/input/style"] + "margin-right:0px;")
def keyPressEvent(self, event):
QtGui.QLineEdit.keyPressEvent(self, event)
if hasattr(self.parent(), 'textArea'):
if event.key() == QtCore.Qt.Key_Return:
self.parent().logSearch(self.text())
if self.parent().textArea.find(self.text()):
self.parent().textArea.ensureCursorVisible()
else:
self.parent().logSearch(self.text())
class PesterLogHighlighter(QtGui.QSyntaxHighlighter):
def __init__(self, parent):
QtGui.QSyntaxHighlighter.__init__(self, parent)
self.searchTerm = ""
self.hilightstyle = QtGui.QTextCharFormat()
self.hilightstyle.setBackground(QtGui.QBrush(QtCore.Qt.green))
self.hilightstyle.setForeground(QtGui.QBrush(QtCore.Qt.black))
def highlightBlock(self, text):
for i in range(0, len(text)-(len(self.searchTerm)-1)):
if unicode(text[i:i+len(self.searchTerm)]).lower() == unicode(self.searchTerm).lower():
self.setFormat(i, len(self.searchTerm), self.hilightstyle)
class PesterLogUserSelect(QtGui.QDialog):
def __init__(self, config, theme, parent):
QtGui.QDialog.__init__(self, parent)
@ -44,6 +70,9 @@ class PesterLogUserSelect(QtGui.QDialog):
item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"]))
self.chumsBox.addItem(item)
self.search = PesterLogSearchInput(theme, self)
self.search.setFocus()
self.cancel = QtGui.QPushButton("CANCEL", self)
self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()'))
@ -58,6 +87,7 @@ class PesterLogUserSelect(QtGui.QDialog):
layout_0 = QtGui.QVBoxLayout()
layout_0.addWidget(instructions)
layout_0.addWidget(self.chumsBox)
layout_0.addWidget(self.search)
layout_0.addLayout(layout_ok)
self.setLayout(layout_0)
@ -65,6 +95,11 @@ class PesterLogUserSelect(QtGui.QDialog):
def selectedchum(self):
return self.chumsBox.currentItem()
def logSearch(self, search):
found = self.chumsBox.findItems(search, QtCore.Qt.MatchStartsWith)
if len(found) > 0 and len(found) < self.chumsBox.count():
self.chumsBox.setCurrentItem(found[0])
@QtCore.pyqtSlot()
def viewActivatedLog(self):
selectedchum = self.selectedchum().text()
@ -91,6 +126,7 @@ class PesterLogViewer(QtGui.QDialog):
self.config = config
self.theme = theme
self.parent = parent
self.mainwindow = parent
global _datadir
self.handle = parent.profile().handle
self.chum = chum
@ -138,7 +174,8 @@ class PesterLogViewer(QtGui.QDialog):
self.logList.sort()
self.logList.reverse()
self.tree = QtGui.QTreeWidget()
self.tree = RightClickTree()
self.tree.optionsMenu = QtGui.QMenu(self)
self.tree.setFixedSize(260, 300)
self.tree.header().hide()
if theme.has_key("convo/scrollbar"):
@ -148,6 +185,7 @@ class PesterLogViewer(QtGui.QDialog):
self.connect(self.tree, QtCore.SIGNAL('itemSelectionChanged()'),
self, QtCore.SLOT('loadSelectedLog()'))
self.tree.setSortingEnabled(False)
child_1 = None
last = ["",""]
for (i,l) in enumerate(self.logList):
@ -160,20 +198,40 @@ class PesterLogViewer(QtGui.QDialog):
child_1.addChild(QtGui.QTreeWidgetItem([self.fileToTime(l)]))
last = self.fileToMonthYear(l)
self.hilight = PesterLogHighlighter(self.textArea)
if len(self.logList) > 0: self.loadLog(self.logList[0])
self.search = PesterLogSearchInput(theme, self)
self.search.setFocus()
self.find = QtGui.QPushButton("Find", self)
font = self.find.font()
font.setPointSize(8)
self.find.setFont(font)
self.find.setDefault(True)
self.find.setFixedSize(40, 20)
layout_search = QtGui.QHBoxLayout()
layout_search.addWidget(self.search)
layout_search.addWidget(self.find)
self.qdb = QtGui.QPushButton("Pesterchum QDB", self)
self.qdb.setFixedWidth(260)
self.connect(self.qdb, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('openQDB()'))
self.ok = QtGui.QPushButton("CLOSE", self)
self.ok.setDefault(True)
self.ok.setFixedWidth(80)
self.connect(self.ok, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()'))
layout_ok = QtGui.QHBoxLayout()
layout_ok.addWidget(self.qdb)
layout_ok.addWidget(self.ok)
layout_ok.setAlignment(self.ok, QtCore.Qt.AlignRight)
layout_logs = QtGui.QHBoxLayout()
layout_logs.addWidget(self.tree)
layout_logs.addWidget(self.textArea)
layout_right = QtGui.QVBoxLayout()
layout_right.addWidget(self.textArea)
layout_right.addLayout(layout_search)
layout_logs.addLayout(layout_right)
layout_0 = QtGui.QVBoxLayout()
layout_0.addWidget(self.instructions)
@ -187,6 +245,10 @@ class PesterLogViewer(QtGui.QDialog):
if len(self.tree.currentItem().text(0)) > len("September 2011"):
self.loadLog(self.timeToFile(self.tree.currentItem().text(0)))
@QtCore.pyqtSlot()
def openQDB(self):
QtGui.QDesktopServices.openUrl(QtCore.QUrl("http://qdb.pesterchum.net/index.php?p=browse", QtCore.QUrl.TolerantMode))
def loadLog(self, fname):
fp = codecs.open("%s/%s/%s/%s/%s" % (self.logpath, self.handle, self.chum, self.format, fname), encoding='utf-8', mode='r')
self.textArea.clear()
@ -199,6 +261,10 @@ class PesterLogViewer(QtGui.QDialog):
self.textArea.setTextCursor(textCur)
self.instructions.setText("Pesterlog with " +self.chum+ " on " + self.fileToTime(str(fname)))
def logSearch(self, search):
self.hilight.searchTerm = search
self.hilight.rehighlight()
def fileToMonthYear(self, fname):
time = strptime(fname[(fname.index(".")+1):fname.index(".txt")], "%Y-%m-%d.%H.%M")
return [strftime("%B", time), strftime("%Y", time)]
@ -217,15 +283,30 @@ class PesterLogText(PesterText):
def mousePressEvent(self, event):
url = self.anchorAt(event.pos())
if url != "":
if url[0] != "#":
if url[0] == "#" and url != "#pesterchum":
self.parent().parent.showMemos(url[1:])
elif url[0] == "@":
handle = unicode(url[1:])
self.parent().parent.newConversation(handle)
else:
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
QtGui.QTextEdit.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
QtGui.QTextEdit.mouseMoveEvent(self, event)
if self.anchorAt(event.pos()):
if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor:
url = self.anchorAt(event.pos())
if url != "" and url[0] != "#":
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
else:
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
def contextMenuEvent(self, event):
textMenu = self.createStandardContextMenu()
if self.textSelected:
self.submitLogAction = QtGui.QAction("Submit to Pesterchum QDB", self)
self.connect(self.submitLogAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('submitLog()'))
textMenu.addAction(self.submitLogAction)
a = textMenu.actions()
a[0].setText("Copy Plain Text")
a[0].setShortcut(self.tr("Ctrl+C"))
textMenu.exec_(event.globalPos())

349
memos.py
View file

@ -8,7 +8,8 @@ from dataobjs import PesterProfile, Mood, PesterHistory
from generic import PesterIcon, RightClickList, mysteryTime
from convo import PesterConvo, PesterInput, PesterText, PesterTabWindow
from parsetools import convertTags, addTimeInitial, timeProtocol, \
lexMessage, colorBegin, colorEnd, mecmd
lexMessage, colorBegin, colorEnd, mecmd, smiledict
from logviewer import PesterLogViewer
def delta2txt(d, format="pc"):
@ -122,14 +123,20 @@ class TimeTracker(list):
def setCurrent(self, timed):
self.current = self.index(timed)
def addRecord(self, timed):
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
try:
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
except TypeError:
(temporal, pcf, when) = pcfGrammar(mysteryTime())
if pcf == "C" or pcf == "?":
return
if timed in self.timerecord[pcf]:
return
self.timerecord[pcf].append(timed)
def getRecord(self, timed):
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
try:
(temporal, pcf, when) = pcfGrammar(timed - timedelta(0))
except TypeError:
(temporal, pcf, when) = pcfGrammar(mysteryTime())
if pcf == "C" or pcf == "?":
return 0
if len(self.timerecord[pcf]) > 1:
@ -154,7 +161,7 @@ class TimeTracker(list):
timed = self.getTime()
return not self.open[timed]
def getTime(self):
if self.current >= 0:
if self.current >= 0:
return self[self.current]
else:
return None
@ -163,7 +170,10 @@ class TimeTracker(list):
return self.getGrammarTime(timed)
def getGrammarTime(self, timed):
mytime = timedelta(0)
(temporal, pcf, when) = pcfGrammar(timed - mytime)
try:
(temporal, pcf, when) = pcfGrammar(timed - mytime)
except TypeError:
(temporal, pcf, when) = pcfGrammar(mysteryTime())
if timed == mytime:
return TimeGrammar(temporal, pcf, when, 0)
return TimeGrammar(temporal, pcf, when, self.getRecord(timed))
@ -234,12 +244,21 @@ _ctag_begin = re.compile(r'<c=(.*?)>')
class MemoText(PesterText):
def __init__(self, theme, parent=None):
QtGui.QTextEdit.__init__(self, parent)
if hasattr(self.parent(), 'mainwindow'):
self.mainwindow = self.parent().mainwindow
else:
self.mainwindow = self.parent()
self.initTheme(theme)
self.setReadOnly(True)
self.setMouseTracking(True)
self.textSelected = False
self.connect(self, QtCore.SIGNAL('copyAvailable(bool)'),
self, QtCore.SLOT('textReady(bool)'))
self.urls = {}
for k in smiledict:
self.addAnimation(QtCore.QUrl("smilies/%s" % (smiledict[k])), "smilies/%s" % (smiledict[k]))
self.connect(self.mainwindow, QtCore.SIGNAL('animationSetting(bool)'),
self, QtCore.SLOT('animateChanged(bool)'))
def initTheme(self, theme):
if theme.has_key("memos/scrollbar"):
@ -255,6 +274,11 @@ class MemoText(PesterText):
parent = self.parent()
window = parent.mainwindow
me = window.profile()
if self.mainwindow.config.animations():
for m in self.urls:
if convertTags(lexmsg).find(self.urls[m].toString()) != -1:
if m.state() == QtGui.QMovie.NotRunning:
m.start()
chumdb = window.chumdb
if chum is not me: # SO MUCH WH1T3SP4C3 >:]
if type(lexmsg[0]) is colorBegin: # get color tag
@ -294,14 +318,19 @@ class MemoText(PesterText):
parent.mainwindow.chatlog.log(parent.channel, joinmsg)
time.openCurrentTime()
def makeSafe(msg):
if msg.count("<c") > msg.count("</c>"):
for i in range(msg.count("<c") - msg.count("</c>")):
msg = msg + "</c>"
return "<span style=\"color:#000000\">" + msg + "</span>"
if type(lexmsg[0]) is mecmd:
memsg = chum.memsg(systemColor, lexmsg, time=time.getGrammar())
window.chatlog.log(parent.channel, memsg)
self.append(convertTags(memsg))
else:
self.append(convertTags(lexmsg))
self.append(makeSafe(convertTags(lexmsg)))
window.chatlog.log(parent.channel, lexmsg)
def changeTheme(self, theme):
self.initTheme(theme)
def submitLogTitle(self):
@ -342,6 +371,9 @@ class PesterMemo(PesterConvo):
self.opAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/opuser"], self)
self.connect(self.opAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('opSelectedUser()'))
self.voiceAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/voiceuser"], self)
self.connect(self.voiceAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('voiceSelectedUser()'))
self.userlist.optionsMenu.addAction(self.addchumAction)
# ban & op list added if we are op
@ -350,7 +382,32 @@ class PesterMemo(PesterConvo):
self.quirksOff.setCheckable(True)
self.connect(self.quirksOff, QtCore.SIGNAL('toggled(bool)'),
self, QtCore.SLOT('toggleQuirks(bool)'))
self.logchum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/viewlog"], self)
self.connect(self.logchum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('openChumLogs()'))
self.invitechum = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/invitechum"], self)
self.connect(self.invitechum, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('inviteChums()'))
self.optionsMenu.addAction(self.quirksOff)
self.optionsMenu.addAction(self.logchum)
self.optionsMenu.addAction(self.invitechum)
self.chanModeMenu = QtGui.QMenu("Memo Settings", self)
self.chanHide = QtGui.QAction("Hidden", self)
self.chanHide.setCheckable(True)
self.connect(self.chanHide, QtCore.SIGNAL('toggled(bool)'),
self, QtCore.SLOT('hideChan(bool)'))
self.chanInvite = QtGui.QAction("Invite-Only", self)
self.chanInvite.setCheckable(True)
self.connect(self.chanInvite, QtCore.SIGNAL('toggled(bool)'),
self, QtCore.SLOT('inviteChan(bool)'))
self.chanMod = QtGui.QAction("Mute", self)
self.chanMod.setCheckable(True)
self.connect(self.chanMod, QtCore.SIGNAL('toggled(bool)'),
self, QtCore.SLOT('modChan(bool)'))
self.chanModeMenu.addAction(self.chanHide)
self.chanModeMenu.addAction(self.chanInvite)
self.chanModeMenu.addAction(self.chanMod)
self.timeslider = TimeSlider(QtCore.Qt.Horizontal, self)
self.timeinput = TimeInput(self.timeslider, self)
@ -405,7 +462,7 @@ class PesterMemo(PesterConvo):
margins = self.mainwindow.theme["memos/margins"]
self.layout.setContentsMargins(margins["left"], margins["top"],
margins["right"], margins["bottom"])
self.setLayout(self.layout)
if parent:
@ -459,23 +516,35 @@ class PesterMemo(PesterConvo):
self.setWindowIcon(PesterIcon(theme["memos/memoicon"]))
t = Template(theme["memos/label/text"])
self.channelLabel.setText(t.safe_substitute(channel=self.channel))
if self.mainwindow.advanced and hasattr(self, 'modes'):
self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
else:
self.channelLabel.setText(t.safe_substitute(channel=self.channel))
self.channelLabel.setStyleSheet(theme["memos/label/style"])
self.channelLabel.setAlignment(self.aligndict["h"][theme["memos/label/align/h"]] | self.aligndict["v"][theme["memos/label/align/v"]])
self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"])
self.channelLabel.setMinimumHeight(theme["memos/label/minheight"])
self.userlist.optionsMenu.setStyleSheet(theme["main/defaultwindow/style"])
self.userlist.setStyleSheet(theme["memos/userlist/style"])
scrolls = "width: 12px; height: 12px; border: 0; padding: 0;"
if theme.has_key("main/chums/scrollbar"):
self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["main/chums/scrollbar/style"] + scrolls, theme["main/chums/scrollbar/handle"], theme["main/chums/scrollbar/downarrow"], theme["main/chums/scrollbar/uparrow"], theme["main/chums/scrollbar/uarrowstyle"], theme["main/chums/scrollbar/darrowstyle"] ))
elif theme.has_key("convo/scrollbar"):
self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s } QScrollBar::add-line { %s } QScrollBar::sub-line { %s } QScrollBar:up-arrow { %s } QScrollBar:down-arrow { %s }" % (theme["memos/userlist/style"], theme["convo/scrollbar/style"] + scrolls, theme["convo/scrollbar/handle"], "display:none;", "display:none;", "display:none;", "display:none;" ))
else:
self.userlist.setStyleSheet("QListWidget { %s } QScrollBar { %s } QScrollBar::handle { %s }" % (theme["memos/userlist/style"], scrolls, "background-color: black;"))
self.userlist.setFixedWidth(theme["memos/userlist/width"])
self.addchumAction.setText(theme["main/menus/rclickchumlist/addchum"])
self.banuserAction.setText(theme["main/menus/rclickchumlist/banuser"])
self.opAction.setText(theme["main/menus/rclickchumlist/opuser"])
self.voiceAction.setText(theme["main/menus/rclickchumlist/voiceuser"])
self.quirksOff.setText(theme["main/menus/rclickchumlist/quirksoff"])
self.logchum.setText(theme["main/menus/rclickchumlist/viewlog"])
self.timeinput.setFixedWidth(theme["memos/time/text/width"])
self.timeinput.setStyleSheet(theme["memos/time/text/style"])
slidercss = "QSlider { %s } QSlider::groove { %s } QSlider::handle { %s }" % (theme["memos/time/slider/style"], theme["memos/time/slider/groove"], theme["memos/time/slider/handle"])
self.timeslider.setStyleSheet(slidercss)
self.timeslider.setStyleSheet(slidercss)
larrow = PesterIcon(self.mainwindow.theme["memos/time/arrows/left"])
self.timeswitchl.setIcon(larrow)
@ -501,18 +570,26 @@ class PesterMemo(PesterConvo):
if item.op:
icon = PesterIcon(self.mainwindow.theme["memos/op/icon"])
item.setIcon(icon)
elif item.voice:
icon = PesterIcon(self.mainwindow.theme["memos/voice/icon"])
item.setIcon(icon)
def addUser(self, handle):
chumdb = self.mainwindow.chumdb
defaultcolor = QtGui.QColor("black")
op = False
voice = False
if handle[0] == '@':
op = True
handle = handle[1:]
if handle == self.mainwindow.profile().handle:
self.userlist.optionsMenu.addAction(self.opAction)
self.userlist.optionsMenu.addAction(self.banuserAction)
self.optionsMenu.addMenu(self.chanModeMenu)
self.op = True
elif handle[0] == '+':
voice = True
handle = handle[1:]
item = QtGui.QListWidgetItem(handle)
if handle == self.mainwindow.profile().handle:
color = self.mainwindow.profile().color
@ -520,10 +597,52 @@ class PesterMemo(PesterConvo):
color = chumdb.getColor(handle, defaultcolor)
item.setTextColor(color)
item.op = op
item.voice = voice
if op:
icon = PesterIcon(self.mainwindow.theme["memos/op/icon"])
item.setIcon(icon)
elif voice:
icon = PesterIcon(self.mainwindow.theme["memos/voice/icon"])
item.setIcon(icon)
self.userlist.addItem(item)
self.sortUsers()
def sortUsers(self):
users = []
listing = self.userlist.item(0)
while listing is not None:
users.append(self.userlist.takeItem(0))
listing = self.userlist.item(0)
users.sort(key=lambda x: ((0 if x.op else 1), (0 if x.voice else 1), x.text()))
for u in users:
self.userlist.addItem(u)
def updateChanModes(self, modes):
if not hasattr(self, 'modes'): self.modes = ""
chanmodes = list(str(self.modes))
if chanmodes and chanmodes[0] == "+": chanmodes = chanmodes[1:]
modes = str(modes)
if modes[0] == "+":
for m in modes[1:]:
if m not in chanmodes:
chanmodes.extend(m)
if modes.find("s") >= 0: self.chanHide.setChecked(True)
if modes.find("i") >= 0: self.chanInvite.setChecked(True)
if modes.find("m") >= 0: self.chanMod.setChecked(True)
elif modes[0] == "-":
for i in modes[1:]:
try:
chanmodes.remove(i)
except ValueError:
pass
if modes.find("s") >= 0: self.chanHide.setChecked(False)
if modes.find("i") >= 0: self.chanInvite.setChecked(False)
if modes.find("m") >= 0: self.chanMod.setChecked(False)
chanmodes.sort()
self.modes = "+" + "".join(chanmodes)
if self.mainwindow.advanced:
t = Template(self.mainwindow.theme["memos/label/text"])
self.channelLabel.setText(t.safe_substitute(channel=self.channel) + "(%s)" % (self.modes))
def timeUpdate(self, handle, cmd):
window = self.mainwindow
@ -603,6 +722,29 @@ class PesterMemo(PesterConvo):
self.userlist.clear()
for n in self.mainwindow.namesdb[self.channel]:
self.addUser(n)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def modesUpdated(self, channel, modes):
c = unicode(channel)
if c == self.channel:
self.updateChanModes(modes)
@QtCore.pyqtSlot(QtCore.QString)
def closeInviteOnly(self, channel):
c = unicode(channel)
if c == self.channel:
self.disconnect(self.mainwindow, QtCore.SIGNAL('inviteOnlyChan(QString)'),
self, QtCore.SLOT('closeInviteOnly(QString)'))
if self.parent():
print self.channel
i = self.parent().tabIndices[self.channel]
self.parent().tabClose(i)
else:
self.close()
msgbox = QtGui.QMessageBox()
msgbox.setText("%s: Invites only!" % (c))
msgbox.setInformativeText("This channel is invite-only. You must get an invitation from someone on the inside before entering.")
msgbox.setStandardButtons(QtGui.QMessageBox.Ok)
ret = msgbox.exec_()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
def userPresentChange(self, handle, channel, update):
@ -613,12 +755,17 @@ class PesterMemo(PesterConvo):
l = update.split(":")
update = l[0]
op = l[1]
reason = l[2]
if update == "nick":
l = h.split(":")
oldnick = l[0]
newnick = l[1]
h = oldnick
if (update in ["join","left", "kick", "+o"]) \
if update[0:1] in ["+", "-"]:
l = update.split(":")
update = l[0]
op = l[1]
if (update in ["join","left", "kick", "+o", "-o", "+v", "-v"]) \
and channel != self.channel:
return
chums = self.userlist.findItems(h, QtCore.Qt.MatchFlags(0))
@ -639,6 +786,18 @@ class PesterMemo(PesterConvo):
self.times[h].removeTime(t.getTime())
if update == "nick":
self.addUser(newnick)
newchums = self.userlist.findItems(newnick, QtCore.Qt.MatchFlags(0))
for nc in newchums:
for c in chums:
if c.op:
nc.op = True
icon = PesterIcon(self.mainwindow.theme["memos/op/icon"])
nc.setIcon(icon)
if c.voice:
nc.voice = True
icon = PesterIcon(self.mainwindow.theme["memos/voice/icon"])
nc.setIcon(icon)
self.sortUsers()
elif update == "kick":
if len(chums) == 0:
return
@ -661,7 +820,7 @@ class PesterMemo(PesterConvo):
opgrammar = self.time.getGrammar()
else:
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memobanmsg(opchum, opgrammar, systemColor, grammar)
msg = chum.memobanmsg(opchum, opgrammar, systemColor, grammar, reason)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, msg)
ttracker.removeTime(ttracker.getTime())
@ -698,13 +857,131 @@ class PesterMemo(PesterConvo):
serverText = "PESTERCHUM:TIME>"+delta2txt(time, "server")
self.messageSent.emit(serverText, self.title())
elif update == "+o":
chums = self.userlist.findItems(h, QtCore.Qt.MatchFlags(0))
if self.mainwindow.config.opvoiceMessages():
chum = PesterProfile(h)
if h == self.mainwindow.profile().handle:
chum = self.mainwindow.profile()
ttracker = self.time
curtime = self.time.getTime()
elif self.times.has_key(h):
ttracker = self.times[h]
else:
ttracker = TimeTracker(timedelta(0))
opchum = PesterProfile(op)
if self.times.has_key(op):
opgrammar = self.times[op].getGrammar()
elif op == self.mainwindow.profile().handle:
opgrammar = self.time.getGrammar()
else:
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memoopmsg(opchum, opgrammar, systemColor)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, msg)
for c in chums:
c.op = True
icon = PesterIcon(self.mainwindow.theme["memos/op/icon"])
c.setIcon(icon)
if unicode(c.text()) == self.mainwindow.profile().handle:
self.userlist.optionsMenu.addAction(self.opAction)
self.userlist.optionsMenu.addAction(self.voiceAction)
self.userlist.optionsMenu.addAction(self.banuserAction)
self.optionsMenu.addMenu(self.chanModeMenu)
self.sortUsers()
elif update == "-o":
self.mainwindow.channelNames.emit(self.channel)
if self.mainwindow.config.opvoiceMessages():
chum = PesterProfile(h)
if h == self.mainwindow.profile().handle:
chum = self.mainwindow.profile()
ttracker = self.time
curtime = self.time.getTime()
elif self.times.has_key(h):
ttracker = self.times[h]
else:
ttracker = TimeTracker(timedelta(0))
opchum = PesterProfile(op)
if self.times.has_key(op):
opgrammar = self.times[op].getGrammar()
elif op == self.mainwindow.profile().handle:
opgrammar = self.time.getGrammar()
else:
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memodeopmsg(opchum, opgrammar, systemColor)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, msg)
for c in chums:
c.op = False
if c.voice:
icon = PesterIcon(self.mainwindow.theme["memos/voice/icon"])
c.setIcon(icon)
else:
icon = QtGui.QIcon()
c.setIcon(icon)
if unicode(c.text()) == self.mainwindow.profile().handle:
self.userlist.optionsMenu.removeAction(self.opAction)
self.userlist.optionsMenu.removeAction(self.voiceAction)
self.userlist.optionsMenu.removeAction(self.banuserAction)
self.optionsMenu.removeAction(self.chanModeMenu.menuAction())
self.sortUsers()
elif update == "+v":
if self.mainwindow.config.opvoiceMessages():
chum = PesterProfile(h)
if h == self.mainwindow.profile().handle:
chum = self.mainwindow.profile()
ttracker = self.time
curtime = self.time.getTime()
elif self.times.has_key(h):
ttracker = self.times[h]
else:
ttracker = TimeTracker(timedelta(0))
opchum = PesterProfile(op)
if self.times.has_key(op):
opgrammar = self.times[op].getGrammar()
elif op == self.mainwindow.profile().handle:
opgrammar = self.time.getGrammar()
else:
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memovoicemsg(opchum, opgrammar, systemColor)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, msg)
for c in chums:
c.voice = True
if not c.op:
icon = PesterIcon(self.mainwindow.theme["memos/voice/icon"])
c.setIcon(icon)
self.sortUsers()
elif update == "-v":
if self.mainwindow.config.opvoiceMessages():
chum = PesterProfile(h)
if h == self.mainwindow.profile().handle:
chum = self.mainwindow.profile()
ttracker = self.time
curtime = self.time.getTime()
elif self.times.has_key(h):
ttracker = self.times[h]
else:
ttracker = TimeTracker(timedelta(0))
opchum = PesterProfile(op)
if self.times.has_key(op):
opgrammar = self.times[op].getGrammar()
elif op == self.mainwindow.profile().handle:
opgrammar = self.time.getGrammar()
else:
opgrammar = TimeGrammar("CURRENT", "C", "RIGHT NOW")
msg = chum.memodevoicemsg(opchum, opgrammar, systemColor)
self.textArea.append(convertTags(msg))
self.mainwindow.chatlog.log(self.channel, msg)
for c in chums:
c.voice = False
if c.op:
icon = PesterIcon(self.mainwindow.theme["memos/op/icon"])
c.setIcon(icon)
else:
icon = QtGui.QIcon()
c.setIcon(icon)
self.sortUsers()
elif c == self.channel and h == "" and update[0] in ["+","-"]:
self.updateChanModes(update)
@QtCore.pyqtSlot()
def addChumSlot(self):
@ -717,19 +994,61 @@ class PesterMemo(PesterConvo):
if not self.userlist.currentItem():
return
currentHandle = unicode(self.userlist.currentItem().text())
self.mainwindow.kickUser.emit(currentHandle, self.channel)
(reason, ok) = QtGui.QInputDialog.getText(self, "Ban User", "Enter the reason you are banning this user (optional):")
if ok:
self.mainwindow.kickUser.emit("%s:%s" % (currentHandle, reason), self.channel)
@QtCore.pyqtSlot()
def opSelectedUser(self):
if not self.userlist.currentItem():
return
currentHandle = unicode(self.userlist.currentItem().text())
self.mainwindow.setChannelMode.emit(self.channel, "+o", currentHandle)
@QtCore.pyqtSlot()
def voiceSelectedUser(self):
if not self.userlist.currentItem():
return
currentHandle = unicode(self.userlist.currentItem().text())
self.mainwindow.setChannelMode.emit(self.channel, "+v", currentHandle)
def resetSlider(self, time, send=True):
self.timeinput.setText(delta2txt(time))
self.timeinput.setSlider()
if send:
self.sendtime()
@QtCore.pyqtSlot()
def openChumLogs(self):
currentChum = self.channel
self.mainwindow.chumList.pesterlogviewer = PesterLogViewer(currentChum, self.mainwindow.config, self.mainwindow.theme, self.mainwindow)
self.connect(self.mainwindow.chumList.pesterlogviewer, QtCore.SIGNAL('rejected()'),
self.mainwindow.chumList, QtCore.SLOT('closeActiveLog()'))
self.mainwindow.chumList.pesterlogviewer.show()
self.mainwindow.chumList.pesterlogviewer.raise_()
self.mainwindow.chumList.pesterlogviewer.activateWindow()
@QtCore.pyqtSlot()
def inviteChums(self):
if not hasattr(self, 'invitechums'):
self.invitechums = None
if not self.invitechums:
(chum, ok) = QtGui.QInputDialog.getText(self, "Invite to Chat", "Enter the chumhandle of the user you'd like to invite:")
if ok:
chum = unicode(chum)
self.mainwindow.inviteChum.emit(chum, self.channel)
self.invitechums = None
@QtCore.pyqtSlot(bool)
def hideChan(self, on):
x = ["-","+"][on]
self.mainwindow.setChannelMode.emit(self.channel, x+"s", "")
@QtCore.pyqtSlot(bool)
def inviteChan(self, on):
x = ["-","+"][on]
self.mainwindow.setChannelMode.emit(self.channel, x+"i", "")
@QtCore.pyqtSlot(bool)
def modChan(self, on):
x = ["-","+"][on]
self.mainwindow.setChannelMode.emit(self.channel, x+"m", "")
@QtCore.pyqtSlot()
def sendtime(self):
me = self.mainwindow.profile()

1265
menus.py

File diff suppressed because it is too large Load diff

View file

@ -38,8 +38,8 @@ def names(cli, *channels):
def channel_list(cli):
cli.send("LIST")
def kick(cli, handle, channel):
cli.send("KICK %s %s" % (channel, handle))
def kick(cli, handle, channel, reason=""):
cli.send("KICK %s %s %s" % (channel, handle, reason))
def mode(cli, channel, mode, options=None):
cmd = "MODE %s %s" % (channel, mode)
@ -76,7 +76,7 @@ def quit(cli, msg='gone'):
cli._end = 1
def user(cli, username, realname=None):
cli.send("USER", realname or username, cli.host, cli.host,
cli.send("USER", realname or username, cli.host, cli.host,
realname or username)
_simple = (
@ -84,6 +84,7 @@ _simple = (
'part',
'nick',
'notice',
'invite',
)
def _addsimple():
import sys
@ -106,6 +107,6 @@ def _addNumerics():
m = sys.modules[__name__]
for num, name in ircevents.numeric_events.iteritems():
setattr(m, name, numericcmd(num, name))
_addNumerics()

View file

@ -23,6 +23,7 @@ numeric_events = {
"003": "created",
"004": "myinfo",
"005": "featurelist", # XXX
"010": "toomanypeeps",
"200": "tracelink",
"201": "traceconnecting",
"202": "tracehandshake",

View file

@ -5,6 +5,7 @@ from datetime import timedelta
from PyQt4 import QtGui
from generic import mysteryTime
from pyquirks import PythonQuirks
_ctag_begin = re.compile(r'(?i)<c=(.*?)>')
_gtag_begin = re.compile(r'(?i)<g[a-f]>')
@ -16,9 +17,15 @@ _handlere = re.compile(r"(\s|^)(@[A-Za-z0-9_]+)")
_imgre = re.compile(r"""(?i)<img src=['"](\S+)['"]\s*/>""")
_mecmdre = re.compile(r"^(/me|PESTERCHUM:ME)(\S*)")
_functionre = re.compile(r"(upper\(|lower\(|scramble\(|reverse\(|\)|\\[0-9]+)")
quirkloader = PythonQuirks()
_functionre = re.compile(r"%s" % quirkloader.funcre())
_groupre = re.compile(r"\\([0-9]+)")
def reloadQuirkFunctions():
quirkloader.load()
global _functionre
_functionre = re.compile(r"%s" % quirkloader.funcre())
def lexer(string, objlist):
"""objlist is a list: [(objecttype, re),...] list is in order of preference"""
stringlist = [string]
@ -247,8 +254,8 @@ def splitMessage(msg, format="ctag"):
if len(okmsg) > 0:
output.append(okmsg)
return output
def addTimeInitial(string, grammar):
endofi = string.find(":")
@ -289,7 +296,7 @@ def timeDifference(td):
elif atd < timedelta(0,3600):
if minutes == 1:
timetext = "%d MINUTE %s" % (minutes, when)
else:
else:
timetext = "%d MINUTES %s" % (minutes, when)
elif atd < timedelta(0,3600*100):
if hours == 1 and leftoverminutes == 0:
@ -300,14 +307,6 @@ def timeDifference(td):
timetext = "%d HOURS %s" % (hours, when)
return timetext
def upperrep(text):
return text.upper()
def lowerrep(text):
return text.lower()
def scramblerep(text):
return "".join(random.sample(text, len(text)))
def reverserep(text):
return text[::-1]
def nonerep(text):
return text
@ -339,8 +338,7 @@ def parseRegexpFunctions(to):
parsed = parseLeaf(nonerep, None)
current = parsed
curi = 0
functiondict = {"upper(": upperrep, "lower(": lowerrep,
"scramble(": scramblerep, "reverse(": reverserep}
functiondict = quirkloader.quirks
while curi < len(to):
tmp = to[curi:]
mo = _functionre.search(tmp)
@ -364,7 +362,7 @@ def parseRegexpFunctions(to):
current.append(to[curi:])
curi = len(to)
return parsed
def img2smiley(string):
string = unicode(string)
@ -374,7 +372,7 @@ def img2smiley(string):
return string
smiledict = {
":rancorous:": "pc_rancorous.gif",
":rancorous:": "pc_rancorous.gif",
":apple:": "apple.gif",
":bathearst:": "bathearst.gif",
":cathearst:": "cathearst.png",
@ -384,7 +382,7 @@ smiledict = {
":blueghost:": "blueslimer.gif",
":slimer:": "slimer.gif",
":candycorn:": "candycorn.gif",
":cheer:": "cheer.gif",
":cheer:": "cheer.gif",
":duhjohn:": "confusedjohn.gif",
":datrump:": "datrump.gif",
":facepalm:": "facepalm.gif",
@ -424,8 +422,79 @@ smiledict = {
":manipulative:": "manipulative.png",
":vigorous:": "vigorous.png",
":perky:": "perky.png",
":acceptant:": "acceptant.png",
":acceptant:": "acceptant.gif",
}
reverse_smiley = dict((v,k) for k, v in smiledict.iteritems())
_smilere = re.compile("|".join(smiledict.keys()))
class ThemeException(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return repr(self.parameter)
def themeChecker(theme):
needs = ["main/size", "main/icon", "main/windowtitle", "main/style", \
"main/background-image", "main/menubar/style", "main/menu/menuitem", \
"main/menu/style", "main/menu/selected", "main/close/image", \
"main/close/loc", "main/minimize/image", "main/minimize/loc", \
"main/menu/loc", "main/menus/client/logviewer", \
"main/menus/client/addgroup", "main/menus/client/options", \
"main/menus/client/exit", "main/menus/client/userlist", \
"main/menus/client/memos", "main/menus/client/import", \
"main/menus/client/idle", "main/menus/client/reconnect", \
"main/menus/client/_name", "main/menus/profile/quirks", \
"main/menus/profile/block", "main/menus/profile/color", \
"main/menus/profile/switch", "main/menus/profile/_name", \
"main/menus/help/about", "main/menus/help/_name", "main/moodlabel/text", \
"main/moodlabel/loc", "main/moodlabel/style", "main/moods", \
"main/addchum/style", "main/addchum/text", "main/addchum/size", \
"main/addchum/loc", "main/pester/text", "main/pester/size", \
"main/pester/loc", "main/block/text", "main/block/size", "main/block/loc", \
"main/mychumhandle/label/text", "main/mychumhandle/label/loc", \
"main/mychumhandle/label/style", "main/mychumhandle/handle/loc", \
"main/mychumhandle/handle/size", "main/mychumhandle/handle/style", \
"main/mychumhandle/colorswatch/size", "main/mychumhandle/colorswatch/loc", \
"main/defaultmood", "main/chums/size", "main/chums/loc", \
"main/chums/style", "main/menus/rclickchumlist/pester", \
"main/menus/rclickchumlist/removechum", \
"main/menus/rclickchumlist/blockchum", "main/menus/rclickchumlist/viewlog", \
"main/menus/rclickchumlist/removegroup", \
"main/menus/rclickchumlist/renamegroup", \
"main/menus/rclickchumlist/movechum", "convo/size", \
"convo/tabwindow/style", "convo/tabs/tabstyle", "convo/tabs/style", \
"convo/tabs/selectedstyle", "convo/style", "convo/margins", \
"convo/chumlabel/text", "convo/chumlabel/style", "convo/chumlabel/align/h", \
"convo/chumlabel/align/v", "convo/chumlabel/maxheight", \
"convo/chumlabel/minheight", "main/menus/rclickchumlist/quirksoff", \
"main/menus/rclickchumlist/addchum", "main/menus/rclickchumlist/blockchum", \
"main/menus/rclickchumlist/unblockchum", \
"main/menus/rclickchumlist/viewlog", "main/trollslum/size", \
"main/trollslum/style", "main/trollslum/label/text", \
"main/trollslum/label/style", "main/menus/profile/block", \
"main/chums/moods/blocked/icon", "convo/systemMsgColor", \
"convo/textarea/style", "convo/text/beganpester", "convo/text/ceasepester", \
"convo/text/blocked", "convo/text/unblocked", "convo/text/blockedmsg", \
"convo/text/idle", "convo/input/style", "memos/memoicon", \
"memos/textarea/style", "memos/systemMsgColor", "convo/text/joinmemo", \
"memos/input/style", "main/menus/rclickchumlist/banuser", \
"main/menus/rclickchumlist/opuser", "main/menus/rclickchumlist/voiceuser", \
"memos/margins", "convo/text/openmemo", "memos/size", "memos/style", \
"memos/label/text", "memos/label/style", "memos/label/align/h", \
"memos/label/align/v", "memos/label/maxheight", "memos/label/minheight", \
"memos/userlist/style", "memos/userlist/width", "memos/time/text/width", \
"memos/time/text/style", "memos/time/arrows/left", \
"memos/time/arrows/style", "memos/time/buttons/style", \
"memos/time/arrows/right", "memos/op/icon", "memos/voice/icon", \
"convo/text/closememo", "convo/text/kickedmemo", \
"main/chums/userlistcolor", "main/defaultwindow/style", \
"main/chums/moods", "main/chums/moods/chummy/icon", "main/menus/help/help", \
"main/menus/help/calsprite", "main/menus/help/nickserv", \
"main/menus/rclickchumlist/invitechum", "main/menus/client/randen"]
for n in needs:
try:
theme[n]
except KeyError:
raise ThemeException("Missing theme requirement: %s" % (n))

View file

@ -1,3 +1,3 @@
#!/bin/sh
python2.6 pesterchum.py
python2.6 pesterchum.py $@

View file

@ -1 +0,0 @@
{"hideOfflineChums": false, "time12Format": true, "tabs": true, "showSeconds": false, "server": "irc.mindfang.org", "soundon": true, "showTimeStamps": false, "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "ircMonster", "twinArmageddons", "cannabisHero", "jetRocket", "adiosToreador", "turntechGodhead", "magmaExploiter", "hannaSongstress", "endlessVoid", "grayscaleVisionary", "corruptedInsanity", "stupidlyBrilliant", "artsyGyarados", "obliviousCrafter", "sporadicAgent", "subtleChaotician", "nareSolee", "apostateCourier", "nocturnalTherapist", "herpaDerp", "clockworkUtopia", "digitalSamurai", "astronomicalMaster", "slipshodBrisant", "genialDustbuster", "hyperdriveTyphoon", "magnificentMiser", "gentleRuffian", "riskRepeats", "globalsoftPrika", "globalsoftPirka", "devonianCritter", "lethargicSerpent", "laughingShisa", "bluntInstrument", "sunilaSeed", "bluntInstrument", "nickServ", "ghostBinoculars", "alGore", "evacipatedBox", "acrylicEmulator", "prettyGemmaiden", "calSprite", "fairytalePorn", "brooklynRage", "computerCyanide", "karkatVantas", "spacedKataz", "musikaTriple", "fooBar", "lotusEater"], "defaultprofile": "testProfile", "block": []}

File diff suppressed because it is too large Load diff

9
pesterchum_debug.py Normal file
View file

@ -0,0 +1,9 @@
# runs pesterchum but appends stdout/err to log file
import subprocess
import datetime
f = open("debug.log", 'a')
d = datetime.datetime.now()
f.write("=== PESTERCHUM DEBUG %s ===\n" % d.strftime("%m-%d-%y %H-%M"))
p = subprocess.Popen("pesterchum.exe", stdout=f, stderr=subprocess.STDOUT)
p.wait()
f.close()

67
pyquirks.py Normal file
View file

@ -0,0 +1,67 @@
import os, sys, imp, re
from PyQt4 import QtGui, QtCore
class PythonQuirks(object):
def __init__(self):
self.home = os.getcwd()
self.quirks = {}
self.last = {}
self.load()
def load(self):
self.last = self.quirks.copy()
self.quirks.clear()
filenames = []
if not os.path.exists(os.path.join(self.home, 'quirks')):
os.mkdir(os.path.join(self.home, 'quirks'))
for fn in os.listdir(os.path.join(self.home, 'quirks')):
if fn.endswith('.py') and not fn.startswith('_'):
filenames.append(os.path.join(self.home, 'quirks', fn))
modules = []
for filename in filenames:
name = os.path.basename(filename)[:-3]
try: module = imp.load_source(name, filename)
except Exception, e:
print "Error loading %s: %s (in pyquirks.py)" % (name, e)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")
msgbox.setText("Error loading %s: %s (in pyquirks.py)" % (name, e))
msgbox.exec_()
else:
if hasattr(module, 'setup'):
module.setup()
self.register(vars(module))
modules.append(name)
for k in self.last:
if k in self.quirks:
if self.last[k] == self.quirks[k]:
del self.quirks[k]
if self.quirks:
print 'Registered quirks:', '), '.join(self.quirks) + ")"
else:print "Warning: Couldn't find any python quirks"
def register(self, variables):
for name, obj in variables.iteritems():
if hasattr(obj, 'command'):
try:
if not isinstance(obj("test"), basestring):
raise Exception
except:
print "Quirk malformed: %s" % (obj.command)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")
msgbox.setText("Quirk malformed: %s" % (obj.command))
msgbox.exec_()
else:
self.quirks[obj.command+"("] = obj
def funcre(self):
if not self.quirks:
return r""
f = r"("
for q in self.quirks:
f = f + q[:-1]+r"\(|"
f = f + r"\)|\\[0-9]+)"
return f

17
quirks/defaults.py Normal file
View file

@ -0,0 +1,17 @@
import random
def upperrep(text):
return text.upper()
upperrep.command = "upper"
def lowerrep(text):
return text.lower()
lowerrep.command = "lower"
def scramblerep(text):
return "".join(random.sample(text, len(text)))
scramblerep.command = "scramble"
def reverserep(text):
return text[::-1]
reverserep.command = "reverse"

54
randomer.py Normal file
View file

@ -0,0 +1,54 @@
from PyQt4 import QtGui, QtCore
class RandomHandler(QtCore.QObject):
def __init__(self, parent):
QtCore.QObject.__init__(self, parent)
self.randNick = "randomEncounter"
self.mainwindow = parent
self.queue = []
# Make True when Lex's new randomEncounter bot (C++) is online
self.running = False
def getRandomer(self):
self.queue.append("?")
self.mainwindow.sendNotice.emit("?", self.randNick)
def setRandomer(self, r):
if r: code = "+"
else: code = "-"
self.queue.append(code)
self.mainwindow.sendNotice.emit(code, self.randNick)
@QtCore.pyqtSlot()
def getEncounter(self):
self.queue.append("!")
self.mainwindow.sendNotice.emit("!", self.randNick)
def incoming(self, msg):
l = msg.split("=")
code = l[0][0]
if code not in self.queue:
return # Ignore if we didn't request this
self.queue.remove(code)
if code == "?":
if l[1][0] == "y":
self.mainwindow.userprofile.setRandom(True)
elif l[1][0] == "n":
self.mainwindow.userprofile.setRandom(False)
elif code in ["+","-"]:
if l[1][0] == "k":
if code == "+":
self.mainwindow.userprofile.setRandom(True)
else:
self.mainwindow.userprofile.setRandom(False)
elif code == "!":
if l[1] == "x":
from PyQt4 import QtGui
msgbox = QtGui.QMessageBox()
msgbox.setText("Unable to fetch you a random encounter!")
msgbox.setInformativeText("Try again later :(")
msgbox.exec_()
return
name = unicode(l[1])
print name
self.mainwindow.newConversation(name)

View file

@ -1,665 +0,0 @@
Welcome to Pesterchum 3.14.1!
WHAT'S NEW?
-----------
* Quirks now have a lower(), scramble(), and reverse() function!
* Timestamps - check your Config!
* Logviewer - View logs right in Pesterchum!
* Quirk ordering - order your quirks so they work right!
* # of users in a memo - You can now see how many users are in a memo.
* @links to users - typing @ before user's name creates a link
that will pester them!
* Support for REPORT and ALT to calSprite built in -
If someone is bothering you, or a canon handle is idle, or
for whatever reason, right click their name and go to "Report"
to report them to a moderator.
If you want to talk to an alt canon handle, just right click
the username!
if you have an alt handle, register it with calSprite!
Here's some tips to help you get started:
- You can import your old Pesterchum contacts by going to
CLIENT->IMPORT and opening your pesterchum.cfg file. This is usually
in the 2.5 base directory or in Tinychum's data folder.
- Some themes can be confusing if you haven't used the program
already! Some hints:
Trollian: Moods are set by clicking the timelines, and you
can add chums by clicking "Chumproll." Moods correspond to the troll
that would most likely exhibit them. You can go offline by hitting the
"Timelines" menu bar.
Gold: Add chums by hitting the two chumpeoples in the upper left
corner. Go offline by clicking the "CHUMHANDLE:" label.
Enamel: Add chums by hitting the "CHUMROLL" label. Go offline by
clicking the upper left hand corner.
- Right-click is your friend! There are useful right click
options on the chumroll, by clicking the chumhandle in a conversation,
online userlist, or the list of memo browsers.
Cool features:
- Importing from old PC. It can already do your chumlist, soon it will
import your quirks from 2.5 and TC as well!
- Profile switching. Instantly switch profiles, loading your color and
quirks with it.
- Theme switching and creation. So far this comes with a few official
themes! But you can also make your own: just make a new directory in
the themes folder with the proper images and style.js file. The
style.js file will be documented soon, but feel free to poke at it.
- Memos. Memos that are a lot more like the ones in the comic and
allow you to appear at multiple times in one chat.
- Quirks: Prefix, suffix, simple replace, regexp replace (like in
2.5), random replacement, and an auto-mispeller :P
- Chum groups. Organize your chums into collapsible groups for easy
management.
- Block/user list
- Add/block chums directly from a conversation, the userlist, or memo
userlist.
- Timestamps saved in logs and shown in conversations if wanted.
- Logging. Logs are output in bbcode (for easy forum posting), html,
and plain text.
- Logviewer for easy log reading inside Pesterchum
- Idling. You can set yourself idle manually, and the computer will
set it for you after 10 minutes.
- Improved /me. Any letters immediately following /me will be
processed correctly. e.g. /me'd rather be fishing -> -- ghostDunk'd
[GD'D] rather be fishing --
- Hyperlinks! Now if someone types http://whatever it will turn into a
link you can just click and follow. No more copy/paste.
- Memo links. Link your friends to your memos.
- Smilies. We've added about 30-40 smilies from the forums. There is a
list later on in this readme.
- Submit quotes directly to the Pesterchum QDB!
FA%
---
Q: Norton says it has a virus and then deletes it!
A: Read this helpful Norton FAQ:
Alright, here's a guide to by-passing Norton:
First, to download Pesterchum:
1: Make sure you're on a Moderator account. Moreso for the Norton steps than these ones.
2: Download the .zip file, not the .exe file.
3: Unzip the .zip file onto memory. Pesterchum should now be installed.
Now, to by-pass Norton:
1: Make sure you're still on a moderator account.
2: Open up Norton.
3: Click on 'Settings' up in the upperright hand corner.
4: Click on 'Anitivirus', off to the upper left. It has a small image of a needle or something similar off to it's side.
5: There's a word that reads 'SONAR protection' halfway to the bottomleft. Off to it's right, there's a bar that's half green. Click on the bar.
6: It will warn you about turning off SONAR. Have it set to turn back on when the system restarts.
7: If done properly, the background for the main page of Norton(what you saw on steps 2-3) has turned an apocaliptic red. Feel free to close Norton now. Keep in mind to stay off suspicious online sites now.
8: Open up Pesterchum, and let the chummy convos begin.
When finished:
First, Log off of Pesterchum. LOG OFF, NOT CLOSE IT.
Then, you can either shut off your comp, and Norton will re-enable SONAR, or you can repeat steps 1-5, except turning the red bar green. If done right, Norton will be it's happy color again.
Keep in mind that you must repeat all of this(other than the download) every time you want to get on Pesterchum.
Hope this is helpful!
(This guide brought to you by the slightly combined efforts of empireomega and Xanaomin)
Q: I can't connect because my school/university/network/stolen wifi is blocking my connection! OR I can't seem to connect to the server at all and I'm not running any firewalls!
A: Edit your pesterchum.js file. Open it up in notepad or something, and then edit the beginning so it looks like this:
{"port": "1413", ....
where the .... is the rest of the gobbledygook there.
Q: The mood buttons on Pesterchum 6.0 don't match up to what it sets your mood to! What gives?
A: The mood names are just there to look canon. It is intentional.
Q: I'm appearing as offline to 2.5 users/other users appear the wrong
mood? What's happeninggggg
A: The 2.5 people decided to change the mood protocol. When I made
this program, I decided to go with Tinychat's original protocol (and
extend it). So some moods will appear wrong between 2.5
users. (*COUGH*tell them to switch to 3.14*COUGH*)
Q: Pesterchum 2.5 users don't get my /me messages correctly!
A: That's because they implemented the /me command differently.
Q: Can we resize the main window?
A: No. This is done so we can offer more flexible UI creation. It's a
lot easier to make themes that look canon this way.
Q: Can we have different chum rolls for different users?
A: No. Instead what we're going to do in a later update is make chum
groups to organize people in your list.
Q: Can we delete profiles?
A: Yes. Go to the profiles directory and delete the corresponding
username file.
Q: You should make it so you can ban specific time frames in memos.
A: This was too complicated to implement, and I don't have the UI
quite figured out. This will probably go in a future update.
DOCUMENTATION
-------------
STARTING
--------
If this is your first time running Pesterchum 3.14, you need to create
a new profile. Just type in your chum handle in the box and click the
color swatch to pick your color. Check the "default" checkbox to make
this your default profile.
BASIC PESTERING
---------------
To begin pestering, first click the "ADD CHUM" button and type in
their pester handle. The handle must be all lower case except for one
capital letter. Once you've added that person, they will appear on
your chumroll. You can double click to begin pestering them, or
right-click to bring up a menu where you can pester them, block them,
or remove them from your chumroll. (Or you can select them and hit
"enter" OR hit the "PESTER" button.)
Once you begin pestering somebody (or they begin pestering you), it
will bring up the conversation window. Here you can type to your
chum. Also remember that if you right-click on the area just above the
Pesterlog, it will bring up a list of options: Quirks Off will turn
your quirks off, Add Chum will add this chum to your list, and Block
will block them. (Those last two options are useful if you are being
pestered by someone you don't have on your list yet!)
While pestering your chum, here are some useful features:
* Type /me to create a system message. "/me facepalms." will generate:
-- ghostDunk [GD] facepalms. --
You can also append 's after /me like so: "/me's computer exploded."
-- ghostDunk's [GD'S] computer exploded. --
In fact, any characters you type after a /me before the space will
be added: "/meing is the Ghost Nation's official pastime."
-- ghostDunking [GDING] is the Ghost Nation's official pastime. --
* Color tags! If you feel the need to talk about The Green Sun or add
some appleberry blast to your conversation, just use color
tags. These work like in TC 1.5: <c=(color)>colored text</c>. But in
PC 3.14, you can use type your color in a lot of different ways:
- You can use the familiar r,g,b method:
"<c=0,255,0>The Green Sun</c>"
- You can use HTML tags:
"<c=#7f7f7f>DURR I'M KARKAT AND I'M A HUGE IDIOT</c>"
- You can even use plain color names:
"<c=red>D4V3 TH1S 1S SO D3C4D3NT</c>"
(list: http://www.w3schools.com/css/css_colornames.asp)
- You don't even have to add the </c> if you are lazy. Just use a
new color tag whenever you want to change colors and PC 3.14 will
add the extra tags for you.
* URLS (anything with http:// in front of it) will automatically be
detected and made into a link you can CLIPK.
* You can also link people to memos by typing "#" and the name of the
menu like so: #R41NBOW_RUMPUS_P4RTYTOWN
Clicking the link will open up the memo select menu.
* Smilies! There are a list of smilies at the end of this document;
they are based on the MSPA Forum smilies. They don't animate, though
:(
* Don't worry about your quirks screwing up any of the above: PC will
apply your quirks AFTER it figures out color codes, links, smilies, etc.
* Pressing the up arrow will cycle through a history of your comments,
so if you want to retype something, you can pull it up.
* You can submit directly to the Pesterchum Quote Database! If you
have a particualarly awesome conversation, you can submit it to the
database by simply highlighting the good part of the conversation,
right clicking it and choosing "Submit to Pesterchum QDB!"
MEMOS
-----
One of the most interesting features to make was the memos, and make
them as close to the comic as I could without actually inventing time
travel. So here is the TIME TUTORIAL:
Joining: When you go CLIENT->MEMOS, you'll see a list of memos pop up
-- those are memos people already have open. To join one, just
highlight one of them. If you want to make a new memo, just type it in
the input. If you'd like to make it secret, so that it doesn't appear
in the list, check "HIDDEN CHANNEL". Then, choose what timeframe you
want to appear to be in. So if you wanted to be in the future, you
could move the slider to the right. You can also enter the time
manually. Then hit JOIN.
Explaining time: Time in memos, unlike Homestuck, will not be relative
to your position. That is, if you choose 4:13 in the future, you will
not see someone who has set their time as "current" (or "0") in the
past: you will see them as "current" and yourself as "future." This is
because we do not have time travel! Memo time setting is basically an
RP mechanic: you are pretending to be from the future! It will also
help keep everyone straight: everyone will see the same thing!
The time slider: The slider shows your current position in the time
stream. If you want to change your time frame, simply move the slider
(or type a time in) and hit GO. This will open a new time frame, and
the next time you type a message, the memo will show that you've
responded to it in that time frame. You can now switch between your
time frames simply by clicking the arrows in the right hand
corner. (THIS COMES IN HANDY IF YOU WANT TO ARGUE WITH YOURSELF.) You
can have any number of open time frames, and the program will number
them in the order in which you open them (like in the comic). You can
have one of your time frames cease responding to the memo by hitting
"CLOSE." If you open that time frame again, the program will remember
the number it originally gave it. If you want to be mysteeeeeeeerious,
you can type in "?" and you will appear as ???.
The memo viewer list: To the right is a list of people currently
browsing the memo. A shade icon next to their name means they are the
"operator" of the memo: meaning they can kick ("ban") people from the
memo and make other people operators as well. A "ban" is not permanent
(like in the comic), and the program will ask if you want to reconnect
to the memo. You kick and op people by right clicking their name in
the window. You can also add them to your chumroll!
Inviting people to your memo: You can link to a memo by simply typing
"#nameofmemo" in any conversation or memo window. So you can say:
CG: NOW YOU, ME, AND EGBERT NEED TO HAVE A CHAT.
CG: CLICK IT.
CG: #FRUITYRUMPUSASSHOLEFACTORY
and it will appear as a link that you can click, which will open the
memo chooser window.
CLIENT MENU
-----------
OPTIONS:
Tabbed Conversations: Turns tabbed conversations on and off. Don't
worry if you do this in the middle of a conversation, PC will save
them for you.
Sounds On: Uncheck to shut it the fuck up.
Hide Offline Chums: Turning this option on will hide all offline chums
off your chumroll.
Show Empty Groups: Turning this option of will show empty groups.
Time Stamps: Turning this on will show timestamps in your chats.
12/24 hour: Formatting for timestamps. Whether you want them in 12 or
24 hour time.
Show Seconds: Turning this on will show the seconds in your timestamps.
MEMOS: Opens the Memo list as above.
USERLIST: Shows a list of all the users that are currently logged onto
Pesterchum. Right-click their names and select "ADD CHUM" to add them
to your chum roll!
IDLE: Make yourself an idle chum. You will appear as idle until you
uncheck this box, or if you *actually* go idle (stop using the
computer) for 10 minutes and then come back.
IMPORT: Imports your old Pesterchum 2.0, 2.5 and Tinychum chum
rolls. This will also import your old quirks from Pesterchum 2.5.
RECONNECT: Forces PC to reconnect to the server.
EXIT: noooooooooooooooooooooooo
PROFILE MENU
------------
THEME: Select a new theme! Be warned that switching themes will change
the user interface, so just... look out for that I guess!
QUIRKS: Opens the quirks menu. More on that below!
TROLLSLUM: Opens up the window where you can view people you've
blocked. You can add and remove people to the list from here as well.
COLOR: Change your text color here!
SWITCH: Switch your profile! You can have any number of profiles, and
PC will save your color, quirks, and theme for that profile. Chumrolls
and block lists are the same for all profiles. Feel free to have
multiple instances of PC running on two or more handles!
CALSPRITE
---------
calSprite is the bot that helps moderate canon handle usage! Simply pester
calSprite with the world "HELP" (turn your quirks off!) and you
will get instructions on how to use calSprite!
QUIRKS
------
There are six kinds of quirks! I'll teach you how to use them all!
(In this section, I will use quotes ("") around things so it's clearer
to see exactly what to type! Don't include these quotes when using
these examples!
Also, note that your quirks will not work until you save them by
hitting "OK" on the Quirk window.
Prefix/Suffix: This will put text before or after everything you
say. So for example, we can use prefixes to emulate part of Nepeta or
Equius' quirks:
PREFIX: ":33 < "
You type: "*ac twitches her friendly whiskers at ct*"
Result:
AC: :33 < *ac twitches her friendly whiskers at ct*
PREFIX: "D --> "
You type: "Hi"
Result:
CT: D --> Hi
Suffixes work the same way, but at the end of the message:
SUFFIX: "!!!"
You type: hey there
Result:
GD: hey there!!!
Remember that it doesn't automatically add a space! You'll need to add
it in (see CT and AC examples again!)
Simple Replace:
This will simply take a set of characters and replace them with other
characters. Let's add a quirk to our Nepeta:
Replace: "ee" With: "33"
You type: "*ac saunters from her dark cave a little bit sleepy from
the recent kill*"
Result:
AC: :33 < *ac saunters from her dark cave a little bit sl33py from the
recent kill*
Let's add two to Equius:
Replace: "loo" With: "100"
Replace: "x" With "%"
You type: "look"
Result:
CT: D --> 100k
You type: "What are you expecting to accomplish with this"
Result:
CT: D --> What are you e%pecting to accomplish with this
Aradia:
Replace: "o" With: "0"
You type: "and the reward would be within our reach"
Result:
AA: and the reward w0uld be within 0ur reach
Notice that it is CASE SENSITIVE. So in the above case, if you typed
"ABSCOND", it would not replace the "O".
Sollux:
Replace: "i" With: "ii"
Replace: "s" With: "2"
Eridan:
Replace: "v" With: "vv"
Replace: "w" With: "ww"
Feferi:
Replace: "h" with: ")("
Replace: "H" with: ")("
Replace: "E" with: "-E"
Regexp Replace:
This is a more complex kind of replacement. Regexp stands for "regular
expression", a kind of programming language (yes, it is a language)
used to find and replace text. PC 3.14 also includes a function to
handle capitalization (upper()). If you want to learn it on your own,
I suggest you start with the Python tutorial
(http://docs.python.org/howto/regex.html) since PC 3.14 uses Python's
regexps. Check out V2.5's tutorial too, as that is a pretty good start
as well.
Let's start with Karkat. Regexps are just like your every day find and
replace: they search for a string that matches what you want to
replace, and replaces it with... the replacement.
Regexp: "(.)" Replace with: "upper(\1)"
Three concepts here. Let's look at the regexp. "(.)" has two things
going on. The first is that ".". In regexp speak, "." is the wildcard:
it will match *any* character -- and just one.
The parentheses tell the regexp to *save* what's inside them so you
can put it back when you replace. That's what the "\1" is for -- it
means, "put the match inside parentheses #1 here". You can have any
number of parentheses.
"upper()" is a function special to PC 3.14 -- it will uppercase
anything inside the parentheses. So in this case, upper will uppercase
"\1" -- which, as you recall is what we found inside the
parentheses. Which was *every* character. So to sum up, it replaces
every character with an uppercase version of that character. WHICH
MAKES YOU TALK LIKE THIS.
Let's look at Terezi next.
Regexp: "[aA]" Replace with: "4"
Regexp: "[iI]" Replace with: "1"
Regexp: "[eE]" Replace with: "3"
Regexp: "(.)" Replace with: "upper(\1)"
We already know what the last line does. But what's up with those
brackets? What's their deal? Basically, in regular expressions,
brackets indicate a list of matching characters. So, basically any
single character within the brackets will be matched. In this case,
either "a" or "A" will be matched and replaced with "4," and likewise,
"i" and "I" will be replaced with "1", and "e" and "E" will be
replaced with "3."
Just like there is an "upper()" function, there is also a "lower()"
function. It acts just like "upper()" but instead makes everything
inside the parentheses lowercase. This allows you to do things like:
Regexp: "(.)" Replace with: "lower(\1)"
You type: "I AM YELLING"
Result:
GD: i am yelling
Along with the upper and lower functions is a "scramble()" function.
The purpose of this function is to randomly scramble anything inside
the parentheses.
Regexp: "(\w)(\w*)(\w)" Replace with: "\1scramble(\2)\3"
You type: "hello there"
Result:
GD: hlelo trhee
This particular regular expression scrambles all of the letters in
the middle of a word. Notice that the "h" and "o" at the beginning
and end of hello remain in place while the other letters are scrambled.
You should also know that "^" is a special character in brackets. If
placed immediately after the opening bracket (like "[^"), then the
brackets instead match every character *except* the ones in the
brackets. So, for example, if you wanted to have a quirk where you
capitalized all your letters *except* o, you'd do this:
Regexp: "([^o])" Replace with: "upper(\1)"
You type: "hello there"
Result:
GD: HELLo THERE
You can also specify a *range* of characters inside the brackets, by
using the "-" character. [a-z] will match any lowercase letter. You
can combine them, too: [a-z0-9] will match any digit and lowercase letter.
There are also different shortcuts for character types:
\d matches any digit; same as [0-9]
\D matches any non-digit; same as [^0-9]
\s matches any spaces
\S matches any non-space
\w matches any alphanumeric character; same as [a-zA-Z0-9_]
\W matches any non-alphanumeric character; same as [^a-zA-Z0-9_]
You can include this inside brackets, too.
There's also a special character, \b. What \b does is make sure that
you are at the beginning or end of a word. So with that knowledge,
let's try Kanaya:
Regexp: \b(\w) Replace with: upper(\1)
You type: "i suggest you come to terms with it"
Result:
GA: I Suggest You Come To Terms With It
Another feature of regular expressions is the ability to match
*repeated* characters. There are three repeat characters: the "*", the
"+", "?", and "{m,n}". They work by playing them after the character,
or character type you want to match. (So, you could say "\s+" or ".*")
The "*" character matches ZERO or more of that character. So, for
example, "f*" would match "f" and "ff" -- and any other character!
That's right, every character counts as matching it zero times. Yeah,
it's weird. I suggest you use...
The "+" character matches ONE or more of that character. So, if we
wanted to have a character that wanted to elongate their s's so that
they used four 's's every time, like sssso, but didn't want to have
eight s's when using words with double s's, like pass, we'd do this:
Regexp: "s+" Replace with: "ssss"
You type: "you shall not pass"
Result:
UU: you sssshall not passss
As for the other two, I can't really think of any useful quirks to be
made with them. But to let you know, "?" matches either 0 or 1 of that
character, so "trolls?" would match "troll" and "trolls". "{m,n}"
matches between m and n characters. (If you leave out 'n', any number
of characters more than m will be matched.) So "s{2,4}" will match
"ss", "sss", and "ssss" and that's it.
Now with repeating expressions, we can do something like make EVERY
other WORD capitalized:
Regexp: "(\w+) (\w+)" Replace with: "upper(\1) \2"
You type: "this is pretty annoying i bet"
Result:
GD: THIS is PRETTY annoying I bet
The \1 matches the first word -- which has been matched because the
word is alphanumeric characters, repeated once or more -- and \2
matches the second word.
Another operator to use is the "|", which will match more than one set
of characters. For example, "black|red" will match "black" or
"red". If you want to match something in the middle of words, you have
to use parentheses: "(black|red) romance" will match "black romance"
and "red romance".
Finally, there are the "^" and "$" characters. Yes, we already did the
"^" character, but this is OUTSIDE of brackets, not INSIDE. "^"
matches the beginning of a message, and "$" matches the end of it. You
can use this to make more sophisticated prefix and suffix
behaviors. For example, if we have a quirk that adds "..." to the end
of all our messages, we can set it up so it doesn't do that if we put
punctuation [?!.] at the end. So:
Regexp: "([^?!.])$" Replace with: "\1..."
This will match the end of any message as long as it doesn't have
"?", "!", or "." at the end. Then it will replace it with whatever the
last character of the sentence was (remember we're replacing it, so we
have to put it back!) and add "..." at the end.
Careful with the beginning and ending replaces -- if you use more than
one, you may not get what you expect because they will ALL be applied,
one after the other! This is a bug in my opinion, that I plan to fix!
Random replace:
Just like the regexp replace, except that instead of just one thing to
replace it with, you give it a list. PC will then choose from that
list randomly. So let's say I want to randomly end my sentences with
either "bro" or "dog":
Regexp: "$" Replace with: "bro" and "dog"
You can also imitate Araida's random "ribbits" in between words:
Regexp: "\s" Replace with: " ribbit ", " ", " ", " ", " ", " ", etc....
where " " is just a blank space added a bunch of times. (You can see
how many blank spaces you've added by clicking on the list.) You have
to add the spaces because each entry has the same chance of being
selected. (Yes, I know this could be improved.) If you add " ribbit "
and 9 spaces, " ribbit " will have a 1/10 chance of being picked.
Also note that if you add more than one prefix or more than one
suffix, it will pick randomly from them instead of adding them both!
Mispeller:
Be careful with thsi one. The mispeller will randomly mispell x% of
the words you type -- where x is the percentage you set the slider
to. I have attempted to mimic SBaHJ mispelling style but whoof knows
what will happen oh god ive created a mosnter
SMILIES
-------
Here's a list of smilies:
:rancorous:
:apple:
:bathearst:
:cathearst:
:woeful:
:pleasant:
:blueghost:
:slimer:
:candycorn:
:cheer:
:duhjohn:
:datrump:
:facepalm:
:bonk:
:mspa:
:gun:
:cal:
:amazedfirman:
:amazed:
:chummy:
:cool:
:smooth:
:distraughtfirman
:distraught:
:insolent:
:bemused:
:3:
:mystified:
:pranky:
:tense:
:record:
:squiddle:
:tab:
:beetip:
:flipout:
:befuddled:
:pumpkin:
:trollcool:
:jadecry:
:ecstatic:
:relaxed:
:discontent:
:devious:
:sleek:
:detestful:
:mirthful:
:manipulative:
:vigorous:
:perky:
:acceptant:

BIN
themes/enamel/leftarrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -10,7 +10,7 @@
"minimize": { "image": "$path/m.gif",
"loc": [300, 32]},
"menubar": { "style": "font-family: 'Century Gothic'; font-size: 14px; color:#9d9d9d" },
"menu" : { "style": "font-family: 'Century Gothic'; font-size: 14px; background-color: #fdb302;border:2px solid #ffff00",
"menu" : { "style": "font-family: 'Century Gothic'; font-size: 14px; color: #000000; background-color: #fdb302;border:2px solid #ffff00",
"menuitem": "margin-right:25px;",
"selected": "background-color: #ffff00",
"loc": [480,30]
@ -19,10 +19,12 @@
"options": "Options",
"memos": "Memos",
"logviewer": "Pesterlogs",
"randen": "Random Encounter",
"userlist": "Userlist",
"addgroup": "Add Group",
"import": "Import",
"reconnect": "Reconnect",
"idle": "Idle",
"idle": "Idle",
"exit": "Exit"},
"profile": {"_name": "Profile",
"switch": "Switch",
@ -31,7 +33,10 @@
"block": "Trollslum",
"quirks": "Quirks"},
"help": { "_name": "Help",
"about": "About" },
"about": "About",
"help": "Help",
"calsprite": "CalSprite",
"nickserv": "NickServ" },
"rclickchumlist": {"pester": "Pester",
"removechum": "Remove Chum",
"blockchum": "Block",
@ -39,9 +44,14 @@
"addchum": "Add Chum",
"viewlog": "View Pesterlog",
"unblockchum": "Unblock",
"removegroup": "Remove Group",
"renamegroup": "Rename Group",
"movechum": "Move To",
"banuser": "Ban User",
"opuser": "Make OP",
"quirksoff": "Quirks Off"
"voiceuser": "Give Voice",
"quirksoff": "Quirks Off",
"invitechum": "Invite Chum"
}
},
"chums": { "style": "text-align: center; border:0px; background-image:url($path/chumbg.png); background-color: #ffe400; background-repeat: no-repeat; color: white; font-family: 'Century Gothic';selection-background-color:#646464; font-size:18px; ",
@ -55,7 +65,7 @@
"loc": [440, 211],
"size": [289, 275],
"userlistcolor": "black",
"moods": {
"moods": {
"chummy": { "icon": "$path/chummy.gif", "color": "black" },
@ -63,7 +73,7 @@
"offline": { "icon": "$path/offline.gif", "color": "#9d9d9d"},
"pleasant": { "icon": "$path/pleasant.gif", "color": "black" },
"distraught": { "icon": "$path/distraught.gif", "color": "black" },
@ -91,7 +101,7 @@
"devious": { "icon": "$path/devious.gif", "color": "red" },
"sleek": { "icon": "$path/sleek.gif", "color": "red" },
"detestful": { "icon": "$path/detestful.gif", "color": "red" },
"mirthful": { "icon": "$path/mirthful.gif", "color": "red" },
@ -110,7 +120,7 @@
}
},
"trollslum": {
"trollslum": {
"style": "background: #fdb302; border:2px solid yellow; font-family: 'Century Gothic'",
"size": [195, 200],
"label": { "text": "TROLLSLUM",
@ -128,7 +138,7 @@
"text": "" },
"currentMood": [1500, 1500]
},
"defaultwindow": { "style": "background: #fdb302; font-family:'Century Gothic';font:bold;selection-background-color:#919191; "
"defaultwindow": { "style": "background: #fdb302; font-family:'Century Gothic';font:bold;selection-background-color:#919191; "
},
"addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px; color: rgba(0, 0, 0, 0%);",
"loc": [443,144],
@ -148,82 +158,82 @@
},
"defaultmood": 0,
"moodlabel": { "style": "",
"loc": [20, 430],
"text": ""
},
"loc": [20, 430],
"text": ""
},
"moods": [
{ "style": "background-image:url($path/mood1.png); border:0px;",
"selected": "background-image:url($path/mood1c.png); border:0px;",
"loc": [0, 258],
"size": [100,110],
"text": "",
"icon": "",
"mood": 0
},
{ "style": "background-image:url($path/mood2.png); border:0px;",
"selected": "background-image:url($path/mood2c.png); border:0px;",
"loc": [106, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 19
},
{ "style": "background-image:url($path/mood3.png); border:0px;",
"selected": "background-image:url($path/mood3c.png); border:0px;",
"loc": [212, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 22
},
{ "style": "background-image:url($path/mood4.png); border:0px;",
"selected": "background-image:url($path/mood4c.png); border:0px;",
"loc": [318, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 4
},
{ "style": "background-image:url($path/mood5.png); border:0px;",
"selected": "background-image:url($path/mood5c.png); border:0px;",
"loc": [0, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 3
},
{ "style": "background-image:url($path/mood6.png); border:0px;",
"selected": "background-image:url($path/mood6c.png); border:0px;",
"loc": [106, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 20
},
{ "style": "background-image:url($path/mood7.png); border:0px;",
"selected": "background-image:url($path/mood7c.png); border:0px;",
"loc": [212, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 5
},
{ "style": "background-image:url($path/mood8.png); border:0px;",
"selected": "background-image:url($path/mood8c.png); border:0px;",
"loc": [318, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 1
},
{ "style": "border:0px;",
"selected": "border:0px;",
"loc": [0, 0],
"size": [100, 100],
"text": "",
"icon": "",
"mood": 2
}
{ "style": "background-image:url($path/mood1.png); border:0px;",
"selected": "background-image:url($path/mood1c.png); border:0px;",
"loc": [0, 258],
"size": [100,110],
"text": "",
"icon": "",
"mood": 0
},
{ "style": "background-image:url($path/mood2.png); border:0px;",
"selected": "background-image:url($path/mood2c.png); border:0px;",
"loc": [106, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 19
},
{ "style": "background-image:url($path/mood3.png); border:0px;",
"selected": "background-image:url($path/mood3c.png); border:0px;",
"loc": [212, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 22
},
{ "style": "background-image:url($path/mood4.png); border:0px;",
"selected": "background-image:url($path/mood4c.png); border:0px;",
"loc": [318, 258],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 4
},
{ "style": "background-image:url($path/mood5.png); border:0px;",
"selected": "background-image:url($path/mood5c.png); border:0px;",
"loc": [0, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 3
},
{ "style": "background-image:url($path/mood6.png); border:0px;",
"selected": "background-image:url($path/mood6c.png); border:0px;",
"loc": [106, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 20
},
{ "style": "background-image:url($path/mood7.png); border:0px;",
"selected": "background-image:url($path/mood7c.png); border:0px;",
"loc": [212, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 5
},
{ "style": "background-image:url($path/mood8.png); border:0px;",
"selected": "background-image:url($path/mood8c.png); border:0px;",
"loc": [318, 382],
"size": [100, 110],
"text": "",
"icon": "",
"mood": 1
},
{ "style": "border:0px;",
"selected": "border:0px;",
"loc": [0, 0],
"size": [100, 100],
"text": "",
"icon": "",
"mood": 2
}
]
},
"convo":
@ -231,7 +241,7 @@
"tabstyle": "background-color: #fdb302; font-family: 'Century Gothic'",
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "border-width: 5px; border-image:url($path/scrollbg.png) 5px; min-height:60px;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px solid #c48a00;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -259,12 +269,12 @@
"ceasepester": "ceased pestering",
"blocked": "blocked",
"unblocked": "unblocked",
"blockedmsg": "did not receive message from",
"blockedmsg": "did not receive message from",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo",
"kickedmemo": "You have been banned from this memo!",
"idle": "is now an idle chum!"
"idle": "is now an idle chum!"
},
"systemMsgColor": "#646464"
},
@ -279,7 +289,7 @@
},
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "border-width: 5px; border-image:url($path/scrollbg.png) 5px; min-height:60px;",
"downarrow": "height:17px;border:0px;",
"downarrow": "height:17px;border:0px;",
"darrowstyle": "image:url();",
"uparrow": "height:17px;border:0px;",
"uarrowstyle": "image:url();"
@ -296,20 +306,21 @@
"userlist": { "width": 150,
"style": "border:2px solid #c48a00; background: white; font-family: 'Century Gothic';selection-background-color:#646464; font-size: 14px; margin-left:0px; margin-right:10px;"
},
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Century Gothic';font:bold;"
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Century Gothic';font:bold;"
},
"slider": { "style": "border: 0px;",
"groove": "",
"handle": ""
},
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"right": "$path/rightarrow.png",
"style": " border:0px; margin-top: 5px; margin-right:10px;"
"style": " border:0px; margin-top: 5px; margin-right:10px;"
}
},
"systemMsgColor": "#646464",
"op": { "icon": "$path/smooth.png" }
"op": { "icon": "$path/smooth.png" },
"voice": { "icon": "$path/voice.png" }
}
}
}

BIN
themes/enamel/voice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

View file

@ -3,9 +3,9 @@
{ "size": [554, 484],
"background-image": "$path/gbbg.png",
"close": { "image": "$path/x.png",
"loc": [535, 45]},
"loc": [539, 47]},
"minimize": { "image": "$path/m.png",
"loc": [515, 48]},
"loc": [519, 50]},
"menu" : { "loc": [214,44] },
"chums": { "style": "border:0px; background-image:url($path/chumbg.png); background-color: rgb(110,110,110); background-repeat: no-repeat; color: white; font-family: 'Arial';selection-background-color:#646464; font-size:16px; ",
"loc": [207, 153],
@ -112,4 +112,4 @@
}
]
}
}
}

BIN
themes/gold/alarm2.wav Normal file

Binary file not shown.

View file

@ -6,25 +6,28 @@
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "PESTERCHUM 7.0",
"close": { "image": "$path/x.png",
"loc": [315, 26]},
"loc": [319, 28]},
"minimize": { "image": "$path/m.png",
"loc": [300, 32]},
"menubar": { "style": "font-family: 'Arial'; font:bold; font-size: 12px;" },
"menu" : { "style": "font-family: 'Arial'; font: bold; font-size: 12px; background-color: #fdb302;border:2px solid #ffff00",
"loc": [304, 34]},
"menubar": { "style": "font-family: 'Arial'; font:bold; font-size: 12px; color: #000000;" },
"menu" : { "style": "font-family: 'Arial'; font: bold; font-size: 12px; color: #000000; background-color: #fdb302;border:2px solid #ffff00",
"menuitem": "margin-right:15px;",
"selected": "background-color: #ffff00",
"loc": [150,22]
},
"sounds": { "alertsound": "$path/alarm.wav",
"ceasesound": "$path/cease.wav" },
"memosound": "$path/alarm2.wav",
"ceasesound": "$path/cease.wav" },
"menus": {"client": {"_name": "Client",
"options": "Options",
"memos": "Memos",
"logviewer": "Pesterlogs",
"randen": "Random Encounter",
"userlist": "Userlist",
"addgroup": "Add Group",
"import": "Import",
"reconnect": "Reconnect",
"idle": "Idle",
"reconnect": "Reconnect",
"idle": "Idle",
"exit": "Exit"},
"profile": {"_name": "Profile",
"switch": "Switch",
@ -33,7 +36,10 @@
"block": "Trollslum",
"quirks": "Quirks"},
"help": { "_name": "Help",
"about": "About" },
"about": "About",
"help": "Help",
"calsprite": "CalSprite",
"nickserv": "NickServ" },
"rclickchumlist": {"pester": "Pester",
"removechum": "Remove Chum",
"report": "Report",
@ -41,16 +47,21 @@
"addchum": "Add Chum",
"viewlog": "View Pesterlog",
"unblockchum": "Unblock",
"removegroup": "Remove Group",
"renamegroup": "Rename Group",
"movechum": "Move To",
"banuser": "Ban User",
"opuser": "Make OP",
"quirksoff": "Quirks Off"
"voiceuser": "Give Voice",
"quirksoff": "Quirks Off",
"invitechum": "Invite Chum"
}
},
"chums": { "style": "border:0px; background-image:url($path/chumbg.png); background-color: rgb(110,110,110); background-repeat: no-repeat; color: white; font-family: 'Arial';selection-background-color:#646464; font-size:14px; ",
"loc": [123, 88],
"size": [190, 65],
"userlistcolor": "white",
"moods": {
"moods": {
"chummy": { "icon": "$path/chummy.png", "color": "white" },
@ -58,7 +69,7 @@
"offline": { "icon": "$path/offline.png", "color": "#bebebe"},
"pleasant": { "icon": "$path/pleasant.png", "color": "white" },
"distraught": { "icon": "$path/distraught.png", "color": "white" },
@ -86,7 +97,7 @@
"devious": { "icon": "$path/devious.png", "color": "red" },
"sleek": { "icon": "$path/sleek.png", "color": "red" },
"detestful": { "icon": "$path/detestful.png", "color": "red" },
"mirthful": { "icon": "$path/mirthful.png", "color": "red" },
@ -105,7 +116,7 @@
}
},
"trollslum": {
"trollslum": {
"style": "background: #fdb302; border:2px solid yellow; font-family: 'Arial'",
"size": [195, 200],
"label": { "text": "TROLLSLUM",
@ -123,7 +134,7 @@
"text": "" },
"currentMood": [129, 176]
},
"defaultwindow": { "style": "background: #fdb302; font-family:'Arial';font:bold;selection-background-color:#919191; "
"defaultwindow": { "style": "background: #fdb302; font-family:'Arial';font:bold;selection-background-color:#919191; "
},
"addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px; color: rgba(0, 0, 0, 0%);",
"loc": [25,0],
@ -143,90 +154,90 @@
},
"defaultmood": 0,
"moodlabel": { "style": "",
"loc": [20, 430],
"text": "MOODS"
},
"loc": [20, 430],
"text": "MOODS"
},
"moods": [
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck1.png); border:0px;",
"loc": [13, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 0
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck2.png); border:0px;",
"loc": [13, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 19
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck3.png); border:0px;",
"loc": [13, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 20
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck4.png); border:0px;",
"loc": [116, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 21
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck5.png); border:0px;",
"loc": [116, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 22
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck6.png); border:0px;",
"loc": [116, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 5
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck7.png); border:0px;",
"loc": [219, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 6
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck8.png); border:0px;",
"loc": [219, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 3
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck9.png); border:0px;",
"loc": [219, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 1
},
{ "style": "border:0px;",
"selected": "border:0px;",
"loc": [13, 175],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 2
}
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck1.png); border:0px;",
"loc": [13, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 0
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck2.png); border:0px;",
"loc": [13, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 19
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck3.png); border:0px;",
"loc": [13, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 20
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck4.png); border:0px;",
"loc": [116, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 21
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck5.png); border:0px;",
"loc": [116, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 22
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck6.png); border:0px;",
"loc": [116, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 5
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck7.png); border:0px;",
"loc": [219, 204],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 6
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck8.png); border:0px;",
"loc": [219, 231],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 3
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck9.png); border:0px;",
"loc": [219, 258],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 1
},
{ "style": "border:0px;",
"selected": "border:0px;",
"loc": [13, 175],
"size": [101, 27],
"text": "",
"icon": "",
"mood": 2
}
]
},
"convo":
@ -234,7 +245,7 @@
"tabstyle": "background-color: #fdb302; font-family: 'Arial'",
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "background-color:#c48a00;min-height:20px;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px solid #c48a00;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -264,12 +275,12 @@
"ceasepester": "ceased pestering",
"blocked": "blocked",
"unblocked": "unblocked",
"blockedmsg": "did not receive message from",
"blockedmsg": "did not receive message from",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo",
"kickedmemo": "You have been banned from this memo!",
"idle": "is now an idle chum!"
"idle": "is now an idle chum!"
},
"systemMsgColor": "#646464"
},
@ -285,7 +296,7 @@
},
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "background-color:#c48a00;min-height:20px;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px solid #c48a00;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -302,20 +313,21 @@
"userlist": { "width": 150,
"style": "border:2px solid #c48a00; background: white; font-family: 'Arial';selection-background-color:#646464; font-size: 14px; margin-left:0px; margin-right:10px;"
},
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;"
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;"
},
"slider": { "style": "border: 0px;",
"groove": "",
"handle": ""
},
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"right": "$path/rightarrow.png",
"style": " border:0px; margin-top: 5px; margin-right:10px;"
"style": " border:0px; margin-top: 5px; margin-right:10px;"
}
},
"systemMsgColor": "#646464",
"op": { "icon": "$path/smooth.png" }
"op": { "icon": "$path/smooth.png" },
"voice": { "icon": "$path/voice.png" }
}
}
}

BIN
themes/gold/voice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

BIN
themes/honk.wav Normal file

Binary file not shown.

BIN
themes/namealarm.wav Normal file

Binary file not shown.

Binary file not shown.

View file

@ -6,25 +6,28 @@
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "PESTERCHUM 6.0",
"close": { "image": "$path/x.png",
"loc": [210, 2]},
"loc": [214, 4]},
"minimize": { "image": "$path/m.png",
"loc": [194, 8]},
"menubar": { "style": "font-family: 'Courier'; font:bold; font-size: 12px;" },
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 12px; background-color: #fdb302;border:2px solid #ffff00",
"loc": [198, 10]},
"menubar": { "style": "font-family: 'Courier'; font:bold; font-size: 12px; color: black;" },
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 12px; color: black; background-color: #fdb302;border:2px solid #ffff00",
"menuitem": "margin-right:10px;",
"selected": "background-color: #ffff00",
"loc": [10,0]
},
"sounds": { "alertsound": "$path/alarm.wav",
"ceasesound": "$path/cease.wav" },
"memosound": "$path/alarm2.wav",
"ceasesound": "$path/cease.wav" },
"menus": {"client": {"_name": "CLIENT",
"options": "OPTIONS",
"memos": "MEMOS",
"logviewer": "PESTERLOGS",
"randen": "RANDOM ENCOUNTER",
"userlist": "USERLIST",
"addgroup": "ADD GROUP",
"import": "IMPORT",
"reconnect": "RECONNECT",
"idle": "IDLE",
"idle": "IDLE",
"exit": "EXIT"},
"profile": {"_name": "PROFILE",
"switch": "SWITCH",
@ -33,7 +36,10 @@
"block": "TROLLSLUM",
"quirks": "QUIRKS"},
"help": { "_name": "HELP",
"about": "ABOUT" },
"about": "ABOUT",
"help": "HELP",
"calsprite": "CALSPRITE",
"nickserv": "NICKSERV" },
"rclickchumlist": {"pester": "PESTER",
"removechum": "REMOVE CHUM",
"report": "REPORT",
@ -41,16 +47,21 @@
"addchum": "ADD CHUM",
"viewlog": "VIEW PESTERLOG",
"unblockchum": "UNBLOCK",
"removegroup": "REMOVE GROUP",
"renamegroup": "RENAME GROUP",
"movechum": "MOVE TO",
"banuser": "BAN USER",
"opuser": "MAKE OP",
"quirksoff": "QUIRKS OFF"
"voiceuser": "GIVE VOICE",
"quirksoff": "QUIRKS OFF",
"invitechum": "INVITE CHUM"
}
},
"chums": { "style": "border:2px solid yellow; background-color: black;color: white;font: bold;font-family: 'Courier';selection-background-color:#646464; ",
"loc": [12, 117],
"size": [209, 82],
"userlistcolor": "white",
"moods": {
"moods": {
"chummy": { "icon": "$path/chummy.png", "color": "white" },
@ -58,7 +69,7 @@
"offline": { "icon": "$path/offline.png", "color": "#646464"},
"pleasant": { "icon": "$path/pleasant.png", "color": "white" },
"distraught": { "icon": "$path/distraught.png", "color": "white" },
@ -86,7 +97,7 @@
"devious": { "icon": "$path/devious.png", "color": "red" },
"sleek": { "icon": "$path/sleek.png", "color": "red" },
"detestful": { "icon": "$path/detestful.png", "color": "red" },
"mirthful": { "icon": "$path/mirthful.png", "color": "red" },
@ -105,7 +116,7 @@
}
},
"trollslum": {
"trollslum": {
"style": "background: #fdb302; border:2px solid yellow; font-family: 'Courier'",
"size": [195, 200],
"label": { "text": "TROLLSLUM",
@ -123,7 +134,7 @@
"text": "" },
"currentMood": [18, 249]
},
"defaultwindow": { "style": "background: #fdb302; font-family:'Courier';font:bold;selection-background-color:#919191; "
"defaultwindow": { "style": "background: #fdb302; font-family:'Courier';font:bold;selection-background-color:#919191; "
},
"addchum": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"pressed" : "background: rgb(255, 255, 255, 30%);",
@ -137,7 +148,7 @@
"size": [71, 22],
"text": ""
},
"block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';",
"block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';",
"pressed" : "background: rgb(255, 255, 255, 30%);",
"loc": [81,202],
"size": [71, 22],
@ -145,73 +156,73 @@
},
"defaultmood": 0,
"moodlabel": { "style": "",
"loc": [20, 430],
"text": "MOODS"
},
"loc": [20, 430],
"text": "MOODS"
},
"moods": [
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck1.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 288],
"size": [104, 22],
"text": "CHUMMY",
"icon": "$path/chummy.png",
"mood": 0
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 308],
"size": [104, 22],
"text": "PALSY",
"icon": "$path/chummy.png",
"mood": 3
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck3.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 328],
"size": [104, 22],
"text": "CHIPPER",
"icon": "$path/chummy.png",
"mood": 4
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 288],
"size": [104, 22],
"text": "BULLY",
"icon": "$path/chummy.png",
"mood": 5
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 308],
"size": [104, 22],
"text": "PEPPY",
"icon": "$path/chummy.png",
"mood": 6
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck4.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 328],
"size": [104, 22],
"text": "RANCOROUS",
"icon": "$path/rancorous.png",
"mood": 1
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck5.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 348],
"size": [209, 22],
"text": "ABSCOND",
"icon": "",
"mood": 2
}
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck1.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 288],
"size": [104, 22],
"text": "CHUMMY",
"icon": "$path/chummy.png",
"mood": 0
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 308],
"size": [104, 22],
"text": "PALSY",
"icon": "$path/chummy.png",
"mood": 3
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck3.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 328],
"size": [104, 22],
"text": "CHIPPER",
"icon": "$path/chummy.png",
"mood": 4
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 288],
"size": [104, 22],
"text": "BULLY",
"icon": "$path/chummy.png",
"mood": 5
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 308],
"size": [104, 22],
"text": "PEPPY",
"icon": "$path/chummy.png",
"mood": 6
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck4.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [117, 328],
"size": [104, 22],
"text": "RANCOROUS",
"icon": "$path/rancorous.png",
"mood": 1
},
{ "style": "text-align:left; border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck5.png); border:2px solid #c48a00; padding: 5px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [12, 348],
"size": [209, 22],
"text": "ABSCOND",
"icon": "",
"mood": 2
}
]
},
"convo":
{"style": "background-color: #fdb302;background-image:url($path/convobg.png);background-repeat: no-repeat; border:2px solid yellow; font-family: 'Courier'",
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: white; border:2px solid #c48a00;",
"handle": "background-color:#c48a00;min-height:20px;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px solid #c48a00;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -231,7 +242,7 @@
"style": "background: white; border:2px solid #c48a00;margin-top:5px; margin-right:10px; margin-left:10px; font-size: 12px;font-family: 'Courier'"
},
"tabwindow" : {
"style": "background-color:#fdb302;border:0px"
"style": "background-color:#fdb302;border:0px"
},
"tabs": {
"style": "background-color: #7f7f7f; font-family: 'Courier';font:bold;font-size:12px;min-height:25px;",
@ -244,12 +255,12 @@
"ceasepester": "ceased pestering",
"blocked": "blocked",
"unblocked": "unblocked",
"blockedmsg": "did not receive message from",
"blockedmsg": "did not receive message from",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo",
"kickedmemo": "You have been banned from this memo!",
"idle": "is now an idle chum!"
"idle": "is now an idle chum!"
},
"systemMsgColor": "#646464"
},
@ -265,7 +276,7 @@
},
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "background-color:#c48a00;min-height:20px;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"downarrow": "height:17px;border:0px solid #c48a00;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px solid #c48a00;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -282,20 +293,21 @@
"userlist": { "width": 150,
"style": "border:2px solid #c48a00; background: white;font: bold;font-family: 'Courier';selection-background-color:#646464; font-size: 12px; margin-left:0px; margin-right:10px;"
},
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;"
"time": { "text": { "width": 75,
"style": " border: 2px solid yellow; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;"
},
"slider": { "style": "border: 0px;",
"groove": "",
"handle": ""
},
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font: bold; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"buttons": { "style": "color: black; font: bold; border: 2px solid #c48a00; font: bold; font-size: 12px; background: yellow; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"right": "$path/rightarrow.png",
"style": " border:0px; margin-top: 5px; margin-right:10px;"
"style": " border:0px; margin-top: 5px; margin-right:10px;"
}
},
"systemMsgColor": "#646464",
"op": { "icon": "$path/op.png" }
"op": { "icon": "$path/op.png" },
"voice": { "icon": "$path/voice.png" }
}
}
}

BIN
themes/pesterchum/voice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

View file

@ -6,26 +6,26 @@
"icon": "$path/trayicon.png",
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "PESTERCHUM",
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 14px; background-color: #fdb302;border:2px solid #ffff00",
"menuitem": "font-size:14px;" },
"menubar": { "style": "font-family: 'Courier'; font:bold; font-size: 14px;" },
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 14px; color: #000000; background-color: #fdb302;border:2px solid #ffff00",
"menuitem": "font-size:14px;" },
"menubar": { "style": "font-family: 'Courier'; font:bold; font-size: 14px; color: #000000;" },
"close": { "image": "$path/x.png",
"loc": [282, 4]},
"loc": [286, 6]},
"minimize": { "image": "$path/m.png",
"loc": [264, 10]},
"loc": [268, 12]},
"chums": { "style": "border:2px solid yellow; background-color: black;color: white;font: bold;font-size:14px;font-family: 'Courier';selection-background-color:#646464; ",
"loc": [15, 70],
"size": [270, 300]
"loc": [15, 70],
"size": [270, 300]
},
"mychumhandle": { "label":
"mychumhandle": { "label":
{ "text": "CHUMHANDLE:",
"loc": [12,415],
"style": "color: black ;font:bold; font-family: 'Courier';"
"style": "color: black ;font:bold; font-family: 'Courier';"
},
"handle": { "loc": [15,435],
"size": [240, 25],
"style": "background-color: black; padding: 3px; padding-left: 25px; color:white; font-family:'Courier'; font:bold; text-align:left; border:2px solid #ffff00;"
},
"style": "background-color: black; padding: 3px; padding-left: 25px; color:white; font-family:'Courier'; font:bold; text-align:left; border:2px solid #ffff00;"
},
"colorswatch": { "loc": [255,435],
"size": [30,25],
"text": "C" },
@ -47,72 +47,72 @@
"text": "BLOCK"
},
"moodlabel": { "style": "font:bold;font-family:'Courier';color:black;",
"loc": [12, 466],
"text": "MOOD:"
},
"loc": [12, 466],
"text": "MOOD:"
},
"moods": [
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold; padding-left:3px;",
"loc": [15, 485],
"size": [135, 30],
"text": "CHUMMY",
"icon": "$path/chummy.png",
"mood": 0
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold; padding-left:3px;",
"loc": [15, 485],
"size": [135, 30],
"text": "CHUMMY",
"icon": "$path/chummy.png",
"mood": 0
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 513],
"size": [135, 30],
"text": "PLEASANT",
"icon": "$path/pleasant.png",
"mood": 3
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 513],
"size": [135, 30],
"text": "PLEASANT",
"icon": "$path/pleasant.png",
"mood": 3
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 541],
"size": [135, 30],
"text": "DISTRAUGHT",
"icon": "$path/distraught.png",
"mood": 4
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 541],
"size": [135, 30],
"text": "DISTRAUGHT",
"icon": "$path/distraught.png",
"mood": 4
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 485],
"size": [135, 30],
"text": "PRANKY",
"icon": "$path/pranky.png",
"mood": 5
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 485],
"size": [135, 30],
"text": "PRANKY",
"icon": "$path/pranky.png",
"mood": 5
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 513],
"size": [135, 30],
"text": "SMOOTH",
"icon": "$path/smooth.png",
"mood": 6
},
{ "style": "text-align:left; background:#ffff00;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 513],
"size": [135, 30],
"text": "SMOOTH",
"icon": "$path/smooth.png",
"mood": 6
},
{ "style": "text-align:left; background:#f00000;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: red; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 541],
"size": [135, 30],
"text": "RANCOROUS",
"icon": "$path/rancorous.png",
"mood": 1
},
{ "style": "text-align:left; background:#f00000;border:2px solid #c48a00;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; color: red; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [148, 541],
"size": [135, 30],
"text": "RANCOROUS",
"icon": "$path/rancorous.png",
"mood": 1
},
{ "style": "text-align:center; border:2px solid #c48a00; background:black;color: white; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; padding: 5px;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 569],
"size": [270, 30],
"text": "ABSCOND",
"icon": "$path/offline.png",
"mood": 2
}
{ "style": "text-align:center; border:2px solid #c48a00; background:black;color: white; font-family:'Courier'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #c48a00; padding: 5px;color: black; font-family:'Courier'; font:bold;padding-left:3px;",
"loc": [15, 569],
"size": [270, 30],
"text": "ABSCOND",
"icon": "$path/offline.png",
"mood": 2
}
]
},
"convo": {
@ -127,4 +127,4 @@
},
"memos":
{ "size": [600,425] }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -6,23 +6,27 @@
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "TROLLIAN",
"close": { "image": "$path/x.png",
"loc": [635, 2]},
"loc": [639, 4]},
"minimize": { "image": "$path/m.png",
"loc": [621, 8]},
"loc": [625, 10]},
"menubar": { "style": "font-family: 'Arial'; font-size: 11px; color: rgba(0,0,0,0);" },
"menu" : { "style": "font-family: 'Arial'; font-size: 11px; background-color: #c2c2c2; border:1px solid #545454;",
"menu" : { "style": "font-family: 'Arial'; font-size: 11px; color: #000000; background-color: #c2c2c2; border:1px solid #545454;",
"selected": "background-color: #545454",
"menuitem": "margin-right:14px;",
"loc": [14,90]
},
"sounds": { "alertsound": "$path/alarm.wav" },
"sounds": { "alertsound": "$path/alarm.wav",
"memosound": "$path/alarm2.wav"},
"menus": {"client": {"_name": "Trollian",
"options": "Options",
"memos": "Memos",
"logviewer": "Pesterlogs",
"randen": "Random Encounter",
"userlist": "Fresh Targets",
"addgroup": "Add Group",
"import": "import U2;",
"idle": "Idle",
"reconnect": "Reconnect",
"idle": "Idle",
"exit": "Abscond"},
"profile": {"_name": "View",
"switch": "Trolltag",
@ -31,7 +35,10 @@
"block": "Chumpdump",
"quirks": "Annoying" },
"help": { "_name": "Help",
"about": "About" },
"about": "About",
"help": "Help",
"calsprite": "CalSprite",
"nickserv": "NickServ" },
"rclickchumlist": {"pester": "Troll",
"removechum": "Trash",
"report": "Remove",
@ -39,9 +46,14 @@
"addchum": "Add Chump",
"viewlog": "View Pesterlog",
"unblockchum": "Mercy",
"removegroup": "Remove Group",
"renamegroup": "Rename Group",
"movechum": "Move To",
"banuser": "Ban",
"opuser": "Promote",
"quirksoff": "Quirks Off" }
"voiceuser": "Let Speak",
"quirksoff": "Quirks Off",
"invitechum": "Invite Chump" }
},
"chums": { "style": "font-size: 12px; background: white; border:0px; font-family: 'Arial';selection-background-color:rgb(200,200,200); ",
"scrollbar": { "style" : "background-color:#c2c2c2;",
@ -55,50 +67,50 @@
"size": [171, 357],
"userlistcolor": "black",
"moods": {
"chummy": { "icon": "$path/chummy.png", "color": "#63ea00" },
"rancorous": { "icon": "$path/rancorous.png", "color": "#7f7f7f" },
"offline": { "icon": "$path/offline.png", "color": "black"},
"pleasant": { "icon": "$path/pleasant.png", "color": "#d69df8" },
"distraught": { "icon": "$path/distraught.png", "color": "#706eba" },
"pranky": { "icon": "$path/pranky.png", "color": "blue" },
"smooth": { "icon": "$path/smooth.png", "color": "red" },
"ecstatic": { "icon": "$path/ecstatic.png", "color": "#99004d" },
"relaxed": { "icon": "$path/relaxed.png", "color": "#078446" },
"discontent": { "icon": "$path/discontent.png", "color": "#a75403" },
"devious": { "icon": "$path/devious.png", "color": "#008282" },
"sleek": { "icon": "$path/sleek.png", "color": "#a1a100" },
"detestful": { "icon": "$path/detestful.png", "color": "#6a006a" },
"mirthful": { "icon": "$path/mirthful.png", "color": "#450077" },
"manipulative": { "icon": "$path/manipulative.png", "color": "#004182" },
"vigorous": { "icon": "$path/vigorous.png", "color": "#0021cb" },
"perky": { "icon": "$path/perky.png", "color": "#406600" },
"acceptant": { "icon": "$path/acceptant.png", "color": "#a10000" },
"protective": { "icon": "$path/protective.png", "color": "white" },
"blocked": { "icon": "$path/blocked.png", "color": "black" }
}
},
"trollslum": {
@ -143,101 +155,101 @@
"moods": [
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck1.png); border:0px;",
"loc": [25, 141],
"size": [20, 270],
"loc": [16, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 17
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck2.png); border:0px;",
"loc": [60, 141],
"size": [20, 270],
"loc": [51, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 9
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck3.png); border:0px;",
"loc": [95, 141],
"size": [20, 270],
"loc": [86, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 11
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck4.png); border:0px;",
"loc": [130, 141],
"size": [20, 270],
"loc": [121, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 1
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck5.png); border:0px;",
"loc": [165, 141],
"size": [20, 270],
"loc": [156, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 16
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck6.png); border:0px;",
"loc": [200, 141],
"size": [20, 270],
"loc": [191, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 8
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck7.png); border:0px;",
"loc": [235, 141],
"size": [20, 270],
"loc": [226, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 10
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck8.png); border:0px;",
"loc": [270, 141],
"size": [20, 270],
"loc": [261, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 14
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck9.png); border:0px;",
"loc": [305, 141],
"size": [20, 270],
"loc": [296, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 15
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck10.png); border:0px;",
"loc": [340, 141],
"size": [20, 270],
"loc": [331, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 13
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck11.png); border:0px;",
"loc": [375, 141],
"size": [20, 270],
"loc": [366, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 12
},
{ "style": "border:0px;",
"selected": "background-image:url($path/moodcheck12.png); border:0px;",
"loc": [410, 141],
"size": [20, 270],
"loc": [401, 141],
"size": [38, 270],
"text": "",
"icon": "",
"mood": 7
},
{ "style": "border:0px;color: rgba(0, 0, 0, 0%);",
"selected": "border:0px; color: rgba(0, 0, 0, 0%);",
"loc": [12, 117],
@ -264,10 +276,10 @@
"style": "background: white; border:2px solid #c2c2c2; font-size: 14px;"
},
"input": {
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; margin-right: 54px; font-size: 12px; height: 19px;"
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; margin-right: 54px; font-size: 12px;"
},
"tabwindow" : {
"style": "background: rgb(190, 19, 4); font-family: 'Arial'"
"style": "background: rgb(190, 19, 4); font-family: 'Arial'"
},
"tabs": {
"style": "",
@ -307,26 +319,27 @@
"style": "background: white; border:2px solid #c2c2c2; font-size: 12px;"
},
"input": {
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; font-size: 12px; height: 19px; margin-bottom: 5px; "
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; font-size: 12px; margin-bottom: 5px; "
},
"margins": {"top": 22, "bottom": 10, "left": 9, "right": 4 },
"userlist": { "width": 125,
"style": "font-size: 12px; background: white; margin-left: 5px; margin-bottom: 5px; border:2px solid #c2c2c2; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200);"
},
"time": { "text": { "width": 75,
"style": "color: black; font:bold; border:1px solid #c2c2c2; background: white; height: 19px;"
"time": { "text": { "width": 75,
"style": "color: black; font:bold; border:1px solid #c2c2c2; background: white; height: 19px;"
},
"slider": { "style": " border:1px solid #c2c2c2;",
"groove": "border-image:url($path/timeslider.png);",
"handle": "image:url($path/acceptant.png);"
},
"buttons": { "style": "border:1px solid #a68168; height: 17px; width: 50px; color: #cd8f9d; font-family: 'Arial'; background: rgb(190, 19, 4); margin-left: 2px;" },
"arrows": { "left": "$path/leftarrow.png",
"buttons": { "style": "border:1px solid #a68168; height: 17px; width: 50px; color: #cd8f9d; font-family: 'Arial'; background: rgb(190, 19, 4); margin-left: 2px;" },
"arrows": { "left": "$path/leftarrow.png",
"right": "$path/rightarrow.png",
"style": "width: 19px; height: 19px; border:0px; margin-left: 2px;"
}
},
"systemMsgColor": "#646464",
"op": { "icon": "$path/op.png" }
"op": { "icon": "$path/op.png" },
"voice": { "icon": "$path/voice.png" }
}
}
}

BIN
themes/trollian/voice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

View file

@ -5,15 +5,15 @@
"icon": "$path/trayicon.png",
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "TROLLIAN",
"menu" : { "style": "font-family: 'Arial'; font: bold; font-size: 14px; background-color: #e5000f;border:2px solid #c20f00" },
"menubar": { "style": "font-family: 'Arial'; font:bold; font-size: 14px;" },
"menu" : { "style": "font-family: 'Arial'; font: bold; font-size: 14px; color: #000000; background-color: #e5000f;border:2px solid #c20f00" },
"menubar": { "style": "font-family: 'Arial'; font:bold; font-size: 14px; color: #000000;" },
"close": { "image": "$path/x.png",
"loc": [280, 2]},
"loc": [272, 0]},
"minimize": { "image": "$path/m.png",
"loc": [260, 8]},
"loc": [248, 2]},
"defaultwindow": { "style": "background: #e5000f; font-family:'Arial';font:bold;selection-background-color:#919191; " },
"chums": { "style": "border:2px solid #ffa4a4; background-color: black;color: white;font: bold;font-size:14px;font-family: 'Arial';selection-background-color:#646464; ",
"moods": {
"moods": {
"chummy": { "icon": "$path/chummy.png", "color": "white" },
@ -21,7 +21,7 @@
"offline": { "icon": "$path/offline.png", "color": "#646464"},
"pleasant": { "icon": "$path/pleasant.png", "color": "white" },
"distraught": { "icon": "$path/distraught.png", "color": "white" },
@ -49,7 +49,7 @@
"devious": { "icon": "$path/devious.png", "color": "red" },
"sleek": { "icon": "$path/sleek.png", "color": "red" },
"detestful": { "icon": "$path/detestful.png", "color": "red" },
"mirthful": { "icon": "$path/mirthful.png", "color": "red" },
@ -65,13 +65,13 @@
"protective": { "icon": "$path/protective.png", "color": "#00ff00" },
"blocked": { "icon": "$path/blocked.png", "color": "black" }
}
},
"mychumhandle": { "label":
}
},
"mychumhandle": { "label":
{ "text": "TROLLTAG:",
"style": "color: black ;font:bold; font-family: 'Arial';"
"style": "color: black ;font:bold; font-family: 'Arial';"
},
"handle": { "style": "background-color: black; padding: 3px; padding-left: 25px; color:white; font-family:'Arial'; font:bold; text-align:left; border:2px solid #ffa4a4;" }
"handle": { "style": "background-color: black; padding: 3px; padding-left: 25px; color:white; font-family:'Arial'; font:bold; text-align:left; border:2px solid #ffa4a4;" }
},
"addchum": { "style": "background: #ffa4a4; border:2px solid #780000; font: bold; color: black; font-family:'Arial';"
},
@ -80,103 +80,103 @@
"block": { "style": "background: #ffa4a4; border:2px solid #780000; font: bold; color: black; font-family:'Arial';"
},
"moodlabel": { "style": "font:bold;font-family:'Arial';color:black;"
},
},
"defaultmood": 1,
"moods": [
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 485],
"size": [135, 30],
"text": "ECSTATIC",
"icon": "$path/estatic.png",
"mood": 7
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 485],
"size": [135, 30],
"text": "ECSTATIC",
"icon": "$path/estatic.png",
"mood": 7
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 513],
"size": [135, 30],
"text": "RELAXED",
"icon": "$path/relaxed.png",
"mood": 8
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 513],
"size": [135, 30],
"text": "RELAXED",
"icon": "$path/relaxed.png",
"mood": 8
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 541],
"size": [135, 30],
"text": "DISCONTENT",
"icon": "$path/discontent.png",
"mood": 9
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [15, 541],
"size": [135, 30],
"text": "DISCONTENT",
"icon": "$path/discontent.png",
"mood": 9
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 485],
"size": [135, 30],
"text": "DEVIOUS",
"icon": "$path/devious.png",
"mood": 10
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 485],
"size": [135, 30],
"text": "DEVIOUS",
"icon": "$path/devious.png",
"mood": 10
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 513],
"size": [135, 30],
"text": "SLEEK",
"icon": "$path/sleek.png",
"mood": 11
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 513],
"size": [135, 30],
"text": "SLEEK",
"icon": "$path/sleek.png",
"mood": 11
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 541],
"size": [135, 30],
"text": "DETESTFUL",
"icon": "$path/detestful.png",
"mood": 12
},
{ "style": "text-align:left; background:#ffa4a4;border:2px solid #780000;color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; color: black; font-family:'Arial'; font:bold; padding-left:3px;",
"loc": [148, 541],
"size": [135, 30],
"text": "DETESTFUL",
"icon": "$path/detestful.png",
"mood": 12
},
{ "style": "text-align:center; border:2px solid #780000; background:black;color: white; font-family:'Arial'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; padding: 5px;color: black; font-family:'Arial'; font:bold;padding-left:3px;",
"loc": [15, 569],
"size": [270, 30],
"text": "ABSCOND",
"icon": "$path/offline.png",
"mood": 2
}
{ "style": "text-align:center; border:2px solid #780000; background:black;color: white; font-family:'Arial'; font:bold;padding-left:3px;",
"selected": "text-align:left; background:white; border:2px solid #780000; padding: 5px;color: black; font-family:'Arial'; font:bold;padding-left:3px;",
"loc": [15, 569],
"size": [270, 30],
"text": "ABSCOND",
"icon": "$path/offline.png",
"mood": 2
}
]
},
"convo": {
"style": "background-color: #e5000f;border:2px solid #780000; font-family: 'Arial';",
"chumlabel": { "style": "margin-bottom: 21px;background: #ffa4a4; color: black; border:0px; font-size: 14px;",
"text" : ":: trolling: $handle ::" },
"textarea": {
"style": "background: white; font-size: 14px;font:bold; border:2px solid #ffa4a4;text-align:center; margin-right:10px; margin-left:10px;font-family: 'Arial'"
},
"text" : ":: trolling: $handle ::" },
"textarea": {
"style": "background: white; font-size: 14px;font:bold; border:2px solid #ffa4a4;text-align:center; margin-right:10px; margin-left:10px;font-family: 'Arial'"
},
"input": { "style": "background: white; border:2px solid #ffa4a4;margin-top:5px; margin-right:10px; margin-left:10px; font-size: 12px;" },
"tabwindow" : {
"style": ""
},
"tabs": {
"style": "",
"selectedstyle": "",
"newmsgcolor": "#ff0000"
},
"scrollbar": null
"tabwindow" : {
"style": ""
},
"tabs": {
"style": "",
"selectedstyle": "",
"newmsgcolor": "#ff0000"
},
"scrollbar": null
},
"memos":
{ "size": [600,425],
"style": "background-color: #e5000f;border:2px solid #780000; font-family: 'Arial';",
"label": { "style": "margin-bottom: 21px;background: #ffa4a4; color: white; border:0px; font-size: 14px;"
},
},
"textarea": {
"style": "background: white; font-size: 14px;font:bold; border:2px solid #ffa4a4;text-align:center; margin-right:10px; margin-left:10px;font-family: 'Arial'"
"style": "background: white; font-size: 14px;font:bold; border:2px solid #ffa4a4;text-align:center; margin-right:10px; margin-left:10px;font-family: 'Arial'"
},
"userlist": { "style": "border:2px solid #780000; background: white;font: bold;font-family: 'Courier';selection-background-color:#646464; font-size: 12px; margin-left:0px; margin-right:10px;"
},
"input": { "style": "background: white; border:2px solid #ffa4a4;margin-top:5px; margin-right:10px; margin-left:10px; font-size: 12px;" },
"time": { "text": { "style": " border: 2px solid #780000; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;"
"time": { "text": { "style": " border: 2px solid #780000; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Arial';font:bold;"
},
"buttons": { "style": "color: black; font: bold; border: 2px solid #780000; font: bold; font-size: 12px; background: #e5000f; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" }
},
@ -189,4 +189,4 @@
},
"scrollbar": null
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

View file

@ -6,25 +6,28 @@
"newmsgicon": "$path/trayicon2.png",
"windowtitle": "Typewriter",
"close": { "image": "$path/x.png",
"loc": [264, 164]},
"loc": [266, 164]},
"minimize": { "image": "$path/m.png",
"loc": [239, 168]},
"loc": [240, 169]},
"menubar": { "style": "font-family: 'Courier'; font:bold; font-size: 12px; color: rgba(0,0,0,0);" },
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 12px; background-color: white;border:2px solid black;",
"menu" : { "style": "font-family: 'Courier'; font: bold; font-size: 12px; color: #000000; background-color: white;border:2px solid black;",
"menuitem": "margin-right:30px;",
"selected": "background-color: black",
"loc": [43,220]
},
"sounds": { "alertsound": "$path/alarm.wav",
"ceasesound": "$path/cease.wav" },
"memosound": "$path/alarm2.wav",
"ceasesound": "$path/cease.wav" },
"menus": {"client": {"_name": "Typewriter",
"options": "Preferences",
"memos": "Bulletin Boards",
"logviewer": "Pesterlogs",
"randen": "Random Encounter",
"userlist": "Userlist",
"addgroup": "Add Group",
"import": "Import",
"idle": "Idle",
"reconnect": "Reconnect",
"idle": "Idle",
"reconnect": "Reconnect",
"exit": "Cease"},
"profile": {"_name": "Ink",
"switch": "Alias",
@ -33,7 +36,10 @@
"block": "Ruffians",
"quirks": "Quirks"},
"help": { "_name": "Assistance",
"about": "About" },
"about": "About",
"help": "Assistance",
"calsprite": "CalSprite",
"nickserv": "NickServ" },
"rclickchumlist": {"pester": "Converse",
"removechum": "Erase User",
"report": "Report User",
@ -41,16 +47,21 @@
"addchum": "Add User",
"viewlog": "View Pesterlog",
"unblockchum": "Forgive",
"removegroup": "Remove Group",
"renamegroup": "Rename Group",
"movechum": "Move To",
"banuser": "Expel User",
"opuser": "Promote",
"quirksoff": "Quirks Off"
"voiceuser": "Let Speak",
"quirksoff": "Quirks Off",
"invitechum": "Invite User"
}
},
"chums": { "style": "border:0px; background-color: white; font: bold;font-family: 'Courier';selection-background-color: black; ",
"loc": [70, 20],
"size": [175,100],
"userlistcolor": "black",
"moods": {
"moods": {
"chummy": { "icon": "$path/chummy.png", "color": "black" },
@ -58,7 +69,7 @@
"offline": { "icon": "$path/offline.png", "color": "#646464"},
"pleasant": { "icon": "$path/pleasant.png", "color": "black" },
"distraught": { "icon": "$path/distraught.png", "color": "black" },
@ -86,7 +97,7 @@
"devious": { "icon": "$path/devious.png", "color": "red" },
"sleek": { "icon": "$path/sleek.png", "color": "red" },
"detestful": { "icon": "$path/detestful.png", "color": "red" },
"mirthful": { "icon": "$path/mirthful.png", "color": "red" },
@ -105,7 +116,7 @@
}
},
"trollslum": {
"trollslum": {
"style": "background: #bebebe; border:2px solid black; font-family: 'Courier'",
"size": [195, 200],
"label": { "text": "Ruffians",
@ -123,7 +134,7 @@
"text": "" },
"currentMood": [0, 0]
},
"defaultwindow": { "style": "background: #bebebe; font-family:'Courier';font:bold;selection-background-color: black; "
"defaultwindow": { "style": "background: #bebebe; font-family:'Courier';font:bold;selection-background-color: black; "
},
"addchum": { "style": "background: rgba(255, 255, 0, 0%); border:0px solid #c48a00; font: bold; color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"pressed" : "background: rgb(255, 255, 255, 30%);",
@ -137,7 +148,7 @@
"size": [70, 15],
"text": ""
},
"block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';",
"block": { "style": "background: rgba(255, 255, 0, 0%); border:2px solid #c48a00; font: bold; color: rgba(255, 255, 0, 0%); font-family:'Courier';",
"pressed" : "background: rgb(255, 255, 255, 30%);",
"loc": [0,0],
"size": [0, 0],
@ -145,26 +156,26 @@
},
"defaultmood": 18,
"moodlabel": { "style": "",
"loc": [20, 430],
"text": "MOODS"
},
"loc": [20, 430],
"text": "MOODS"
},
"moods": [
{ "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck1.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [95, 323],
"size": [62, 9],
"text": "",
"icon": "",
"mood": 18
},
{ "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [165, 323],
"size": [70, 9],
"text": "",
"icon": "",
"mood": 2
}
{ "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck1.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [95, 323],
"size": [62, 9],
"text": "",
"icon": "",
"mood": 18
},
{ "style": "text-align:left; border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier'",
"selected": "text-align:left; background-image:url($path/moodcheck2.png); border:0px solid #c48a00; padding: 0px;color: rgba(0, 0, 0, 0%); font-family:'Courier';",
"loc": [165, 323],
"size": [70, 9],
"text": "",
"icon": "",
"mood": 2
}
]
},
"convo":
@ -195,12 +206,12 @@
"ceasepester": "ceased pestering",
"blocked": "blocked",
"unblocked": "unblocked",
"blockedmsg": "did not receive message from",
"blockedmsg": "did not receive message from",
"openmemo": "opened memo on board",
"joinmemo": "responded to memo",
"closememo": "ceased responding to memo",
"kickedmemo": "You have been banned from this memo!",
"idle": "is now an idle chum!"
"idle": "is now an idle chum!"
},
"systemMsgColor": "#646464"
},
@ -216,7 +227,7 @@
},
"scrollbar": { "style" : "padding-top:17px; padding-bottom:17px;width: 18px; background: rgba(255, 255, 0, 0%); border:0px;",
"handle": "background-color:black;min-height:20px;",
"downarrow": "height:17px;border:0px;",
"downarrow": "height:17px;border:0px;",
"darrowstyle": "image:url($path/downarrow.png);",
"uparrow": "height:17px;border:0px;",
"uarrowstyle": "image:url($path/uparrow.png);"
@ -233,20 +244,21 @@
"userlist": { "width": 150,
"style": "border:2px solid black; background: white;font: bold;font-family: 'Courier';selection-background-color:black; font-size: 12px; margin-left:0px; margin-right:10px;"
},
"time": { "text": { "width": 75,
"style": " border: 2px solid black; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;"
"time": { "text": { "width": 75,
"style": " border: 2px solid black; background: white; font-size: 12px; margin-top: 5px; margin-right: 5px; margin-left: 5px; font-family:'Courier';font:bold;"
},
"slider": { "style": "border: 0px;",
"groove": "",
"handle": ""
},
"buttons": { "style": "color: black; font: bold; border: 2px solid black; font: bold; font-size: 12px; background: white; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"buttons": { "style": "color: black; font: bold; border: 2px solid black; font: bold; font-size: 12px; background: white; margin-top: 5px; margin-right: 5px; margin-left: 5px; padding: 2px; width: 50px;" },
"arrows": { "left": "$path/leftarrow.png",
"right": "$path/rightarrow.png",
"style": " border:0px; margin-top: 5px; margin-right:10px;"
"style": " border:0px; margin-top: 5px; margin-right:10px;"
}
},
"systemMsgColor": "#646464",
"op": { "icon": "$path/protective.png" }
"op": { "icon": "$path/protective.png" },
"voice": { "icon": "$path/voice.png" }
}
}
}

BIN
themes/typewriter/voice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

170
trollquirks.mkdn Normal file
View file

@ -0,0 +1,170 @@
Troll Quirks
============
Karkat
------
<pre>
REGEXP: "(.)"
REPLACED WITH: "upper(\1)"
</pre>
Aradia
------
<pre>
REGEXP: "[oO]"
REPLACE WITH: "0"
</pre>
#####After Prototyping
<pre>
RANDOM REGEXP: "\s"
REPLACED WITH: " ribbit ", " ", " ", " ", " ", " ", etc....
</pre>
Tavros
------
<pre>
REGEXP: "\b(\w)(\w*)"
REPLACED WITH: "lower(\1)upper(\2)"
</pre>
<pre>
REGEXP: "\.?"
WITH: ","
</pre>
Sollux
------
#####Pre-blind
<pre>
REGEXP: "[iI]"
REPLACE WITH: "\1\1"
</pre>
<pre>
REGEXP: "[sS]"
REPLACE WITH: "2"
</pre>
<pre>
REGEXP: "\btoo?\b"
REPLACE WITH: "two"
</pre>
#####Blind
<pre>
REGEXP: "[oO]"
REPLACE WITH: "0"
</pre>
Nepeta
------
<pre>
PREFIX: ":33 &lt; "
</pre>
<pre>
REGEXP: "[eE][eE]"
REPLACE WITH: "33"
</pre>
Kanaya
------
<pre>
REGEXP: "\b(\w)"
REPLACE WITH: "upper(\1)
</pre>
Terezi
------
<pre>
REGEXP: "[aA]"
REPLACE WITH: "4"
</pre>
<pre>
REGEXP: "[iI]"
REPLACE WITH: "1"
</pre>
<pre>
REGEXP: "[eE]"
REPLACE WITH: "3"
</pre>
<pre>
REGEXP: "(.)"
REPLACE WITH: "upper(\1)"
</pre>
Vriska
------
<pre>
REGEXP: "[bB]"
REPLACE WITH: "8"
</pre>
<pre>
RANDOM REGEXP: "([aeiouAEIOU])"
REPLACE WITH: "\1\1\1\1\1\1\1\1", "\1", "\1", "\1", "\1", "\1", etc........
</pre>
<pre>
RANDOM REGEXP: "([\.\?,!]$)"
REPLACE WITH: "\1\1\1\1\1\1\1\1", "\1", "\1", "\1", "\1", "\1", etc........
</pre>
<pre>
REPLACE: ":"
WITH: "::::"
</pre>
Keep in mind that the RANDOM REGEXP ones require the extra "\\1"s to be added in order to not happen all the time. If you want those quirks to happen less often, add more "\\1".
Equius
------
<pre>
PREFIX: "D --&gt; "
</pre>
<pre>
REGEXP: "[lL][oO][oO]"
REPLACE WITH: "100"
</pre>
<pre>
REGEXP: "[xX]"
REPLACE WITH: "%"
</pre>
<pre>
REGEXP: "(\b[sS][tT][rR][oO][nN][gG]\w*)"
REPLACE WITH: "upper(\1)"
</pre>
<pre>
REGEXP: "[oO][oO]"
REPLACE WITH: "00"
</pre>
Gamzee
------
#####Version 1: "HoNk HoNk"
<pre>
REGEXP: "([a-zA-Z])([a-zA-Z]?)"
REPLACED WITH: "upper(\1)\2"
</pre>
#####Version 2: "HoNk hOnK"
<pre>
REGEXP: "([\w\s])([\w\s]?)"
REPLACED WITH: "upper(\1)\2"
</pre>
Eridan
------
<pre>
REGEXP: "([vVwW])"
REPLACE WITH: "\1\1"
</pre>
<pre>
REGEXP: "ing\b"
REPLACE WITH: "in"
</pre>
Feferi
------
<pre>
REGEXP: [hH]
REPLACE WITH: ")("
</pre>
<pre>
REPLACE: "E"
WITH: "-E"
</pre>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Some files were not shown because too many files have changed in this diff Show more