From 8e110fe19f15185636952299fa4bdd8d9be310e9 Mon Sep 17 00:00:00 2001 From: Botond Hende Date: Tue, 23 Apr 2024 21:29:06 +0200 Subject: initial commit --- .gitignore | 3 + README.md | 12 + resources/data.json | 550 ++++++++++++++++++++++++++++ resources/ram.png | Bin 0 -> 202061 bytes run.sh | 1 + src/__init__.py | 0 src/__main__.py | 124 +++++++ src/modules/__init__.py | 0 src/modules/butlerWidget.py | 715 +++++++++++++++++++++++++++++++++++++ src/modules/data_reader.py | 59 ++++ src/modules/helpWidget.py | 31 ++ src/modules/maidWidget.py | 845 ++++++++++++++++++++++++++++++++++++++++++++ src/modules/masterWidget.py | 677 +++++++++++++++++++++++++++++++++++ 13 files changed, 3017 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 resources/data.json create mode 100644 resources/ram.png create mode 100755 run.sh create mode 100644 src/__init__.py create mode 100644 src/__main__.py create mode 100644 src/modules/__init__.py create mode 100644 src/modules/butlerWidget.py create mode 100644 src/modules/data_reader.py create mode 100644 src/modules/helpWidget.py create mode 100644 src/modules/maidWidget.py create mode 100644 src/modules/masterWidget.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44a9107 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +**/__pycache__/ +**/*.pyc diff --git a/README.md b/README.md new file mode 100644 index 0000000..0e7bd30 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# RMG - Random Maid Generator +## Character description +Character generator for the infamous Maid RPG. + +This is a small Python project I created when I was still in the early phase of learning programming. It is UGLY. However it works (mostly). + +## Backstory +Originally it was created in Python 2 with PyQt4. Much of the sourcecode had been lost, and I could only fully recover it by decompiling an exe version I created back then with py2exe. After that I had to run a PyQt4 >> PyQt5 conversion. I'm planning to clean up the code in the future. + +## Necessary tools +* Python 3 +* PyQt5 diff --git a/resources/data.json b/resources/data.json new file mode 100644 index 0000000..3d89b49 --- /dev/null +++ b/resources/data.json @@ -0,0 +1,550 @@ +{ + "common" : { + "colors" : { + "rare" : [ "Red", "Blue", "Yellow", "White", "Black", "Transparent/Rainbow" ], + "double_chance" : [ "Purple", "Orange", "Pink", "Brown", "Vermillion", "Green", "Sky blue", "Navy", "Indigo", + "Cream", "Beige", "Gold", "Gray", "Silver", "Metallic"] + }, + "stress_explosions" : [ + ["Alcohol/Drugs", "You drink alcohol (or drugs) until you can't remember or care."], + ["Stealing", "You steal valuables from the mansion or from other maids."], + ["Violence", "You unleash violence on the other maids and the master."], + ["Gambling", "You use every penny you have for gambling."], + ["Racing", "You get into whatever car/vehicle is handy and go for a drive at at least twice the speed limit."], + ["Teasing", "You start persistently tormenting the other maids."], + ["Mischief", "You start playing troublesome tricks on the master and the other maids."], + ["Running Away", "You run away from the mansion."], + ["Complaining", "You start incessantly complaining to the master and other maids."], + ["Seclusion", "You go into your room and won't come out, not even for food."], + ["Crying", "You start crying. There's no need for an Affection check for this."], + ["Rampage", "You use anything you can lay your hands on to run around destroying things around the mansion."], + ["Shopping", "You go crazy spending your money on shopping."], + ["Sleep", "You spend all day sleeping."], + ["Binge", "You go crazy eating."], + ["Prayer", "You escape through religion, relentlessly praying to heaven for protection."], + ["Spoiled Child", "You act like a spoiled child, making demands of the master."], + ["Player Choice", "Let the player to your left decide for you."] + ] + }, + + "maid" : { + "weapons" : [ + ["Mop/Broom", "You fight with a broom or mop. This is a maid's basic fighting style."], + ["Stun Gun", "You keep a stun gun ready to attack enemies."], + ["Kitchen Knife", "You wield some kind of ordinary kitchen knife."], + ["Frying Pan", "You hit things with a frying pan."], + ["Vase/Bottle/Pot", "When trouble happens, you grab something suitable from around the mansion and wave it around or throw it."], + ["Hand-to-Hand", "You fight with your bare hands, whether striking attacks or submission moves."], + ["Revolver", "You fight with a revolver. Feel free to decide what kind."], + ["Machinegun", "You wield a machinegun. Feel free to decide what kind."], + ["Rifle", "You wield a rifle. Feel free to decide what kind."], + ["Bomb/Grenade", "You use bombs, grenades, or maybe plastic explosives."], + ["Bazooka", "When a fight breaks out you pull out a big-ass bazooka."], + ["Ray Gun", "It might look like a prop of a 50s sci-fi B movie, but the ray gun you're packing really does hurt people."], + ["Metal Pipe/Nail Bat", "You use some crude weapon like a pipe or a bat with nails in it."], + ["Hammer", "You wield a hammer, whether a small throwing hammer, a big warhammer, or one of the squeaky toy variety."], + ["Scythe", "You wield a big scythe worthy of the Grim Reaper."], + ["Kung Fu Weapon", "Nunchucks, Three-Section Staff, Tonfa, Sai, Tai Chi Sword, etc."], + ["Chainsaw", "Never mind how loud it is you fight with a chainsaw!"], + ["Western Sword", "A long sword, rapier, flamberge, two-handed sword, etc., etc."], + ["Wooden Sword/Staff", "You wield bokken - Japanese-style wooden sword - or a staff."], + ["Axe/Hatchet", "A tomahawk, battle axe, halberd, etc."], + ["Morningstar", "Basically a mace with spikes. You can have a flail instead if you like."], + ["Whip", "A normal whip, a cat of nine tails, a metal whip, etc."], + ["Spear/Lance", "A spear, lance, javelin, etc."], + ["Exotic Weapon", "A boomerang, qatar, African throwing irons, etc."], + ["Knife/Scalpel", "You attack with a knife or scalpel. You can throw it too, and it can be a large dagger if you like."], + ["Chain/Rope", "You attack with a chain or rope."], + ["Claws", "You attack with claws, a bagh nakh, cestus, or some other claw-like weapon."], + ["Katana", "You wield a katana, or possibly a kusarigama or some other traditional Japanese weapon."], + ["Shuriken/Kunai", "You have a seemingly unlimited supply of shuriken (throwing stars), or kunai (ninja throwing knives)."], + ["Halberd/Pole Arm", "Naginata, halberd, bardiche, or some other kind of pole arm."], + ["Summoning", "You are able to summon some kind of special being to attack. You can decide what you summon and how it attacks."], + ["Magic", "You use magic to attack."], + ["Psychic Powers", "Well, you have some kind of psychic/super power that you use to attack. You can decide the details."], + ["Book", "You wield a book as a blunt instrument, and possibly tear out pages, to attack."], + ["Internal Weapons", "You have some kind of weapons installed in your body."], + ["Religious Symbol", "You can use a cross, prayer wheel, paper charm, or other seemingly harmless religious symbol to deliver attacks."] + ], + "types" : [ + ["Lolita", "Childish, young, innocent, cute, sweet.", [-1, 0, 0, 0, 1, 0], "Luck +1, Athletics -1"], + ["Sexy", "Charming, coquettish, womanly body, glamorous.", [0, 0, 0, 1, 0, -1], "Cunning +1, Will -1"], + ["Pure", "Pure, maidenly, clean, fragile.", [0, 1, 0, -1, 0, 0], "Affection +1, Cunning -1"], + ["Cool", "Composed, expressionless, unflappable, doll-like.", [0, -1, 1, 0, 0, 0], "Skill +1, Affection -1"], + ["Boyish", "Wild, energetic, vigorous, at first glance looks like a boy.", [1, 0, -1, 0, 0, 0], "Athletics +1, Skill -1"], + ["Heroine", "Earnest, single-minded, tries her very best.", [0, 0, 0, 0, -1, 1], "Will +1, Luck -1"] + ], + "qualities" : [ + ["Glasses", "You wear glasses, and can't use contact lenses. The frame design can be whatever you want.", null], + ["Freckles", "You have freckles.", null], + ["Sickly", "You've got an incurable disease. However, this doesn't adversely affect your attributes. Choose your own symptoms.", null], + ["Quiet", "You have a cool, subtle demeanor. No, there are no rules regarding how often you speak.", null], + ["Easygoing", "You take things slow and calm, at your own pace. This doesn't affect your attributes.", null], + ["Neat Freak", "You're obsessed with cleanliness, and can't let the tiniest bit of dirt go unnoticed.", null], + ["Brown Skin", "Your skin is a dark brown color. It could be natural, or a tan.", null], + ["Albino", "You have no pigment. You're not necessarily completely colorless, this could simply be a very pale complexion.", null], + ["Shy", "You're very shy. Don't forget to remain silent when encountering NPCs you haven't met before.", null], + ["Actually A Guy", "You're actually a guy (cross-dresser?). Or possibly a hermaphrodite.", null], + ["Overactive Imagination", "You frequently get caught up in your own imaginary world, or else tend to daydream a lot.", null], + ["Greedy", "You will do absolutely anything for the sake of money.", null], + ["Elf Ears", "You have long, pointed ears.", null], + ["Nekomimi", "This varies a bit depending on the setting, but you're a catgirl, with the ears and possibly tail of a cat.", null], + ["Android/Gynoid", "You're not human, but rather a human-looking robot. Parts of your body are very obviously artificial.", null], + ["Vampire", "You are a vampire, with long fangs. Be sure to act . . . vampiric.", null], + ["Princess", "You're actually the daughter of a family of even greater standing than the master. Depending on the setting, you could even be from another country's royal family. Whether you are in disguise or not is up to you.", null], + ["Angel/Devil", "You are a being from another world charged with judging good and evil. The design and the details of your origins are up to you.", null], + ["Uniform", "You've managed to make a special arrangement with your uniform.\n>> Uniform table", [ + ["Tights", "In place of a skirt, you wear tights of some color. Athletic, colorful, sexy, or weird (leopard pattern, RAWR!) it's up to you. (For the purposes of the maid uniform rules, treat these as a skirt)"], + ["China Dress", "You wear a Chinese-style cheongsam maid uniform. (For the purposes of the rules, treat this as a one-piece maid uniform)."], + ["Armor", "Your maid uniform is actually a stylized suit of metal armor."], + ["Bondage", "Your maid uniform is made of shiny rubber or leather, and generally a bit suspicious."], + ["Miniskirt", "Your skirt is very short, to the point where one can almost see its contents."], + ["Kappougi", "Instead of a Western maid uniform, you wear a Japanese-style one with a kimono and an apron over it."] + ] + ], + ["Symbol", "You have some kind of special mark on your uniform of headdress.\n>> Symbol table", [ + ["Skull", "Your headdress, apron, necktie, forehead, or chest has a skull mark."], + ["Bat", "Your headdress, apron, necktie, forehead, or chest has a bat symbol."], + ["Cross", "Your headdress, apron, necktie, forehead, or chest has a cross on it."], + ["Yin-Yang", "Your headdress, apron, necktie, forehead, or chest has a yin-yang symbol."], + ["Star", "Your headdress, apron, necktie, forehead, or chest has a five- or six-pointed star mark."], + ["Card suit", "Your headdress, apron, necktie, forehead, or chest has is marked with one of the four suits from playing cards: hearts, diamonds, clubs or spades."] + ] + ], + ["Delinquent", "Something about you is very much like a delinquent.\n>> Delinquent table", [ + ["Cigarettes", "You've always got a cigarette in your mouth, or are chomping on a cigar."], + ["Tattoo", "Somewhere on your body - or maybe even all over it - you have a tattoo."], + ["Sunglasses", "You always wear sunglasses or mirrorshades. Even at night."], + ["Bad Expression", "You have a perpetual unpleasant facial expression (as if you're always angry, or always about to kick ass at any moment), and this makes first meetings difficult."], + ["Piercings", "You have piercings, and not just in your ears, but perhaps your forehead, lips, eyelids, chin, etc."], + ["Rough Speak", "You talk like a gangster, be it a Mafioso or a street ganger."] + ] + ], + ["Accent", "You have an unusual way of speaking.\n>> Accent table", [ + ["Southern", "Y'all talk like some kinda' country bumpkin or somethin', from down in the American South."], + ["British", "You talk with a British accent of some kind. We'll leave it up to you what kind specifically. If you are already from the UK in real life, then you are now DOUBLE BRITISH. Or choose Scottish or Welsh."], + ["Pidgin English", "You come from a country/society where English is taught as a pidgin language. You might sound like a Japanese salaryman or pop idol ('Body Feels Exit!'). Pick a country and go with it."], + ["Meow", "You like to sprinkle cat sounds in your speech every now and then."], + ["Knight", "You sound like a knight from a movie, or possibly a Renaissance Faire reject. Remember to say 'Thou art' and whatnot a lot."], + ["Foreigner", "Pick a foreign nationality for your Maid other than Japanese. American (Brooklyn, Texas), French, Russian, Mexican, Nigerian, Indian, Canadian, etc."] + ] + ], + ["Hairstyle", "You have a special hairstyle.\n>> Hairstyle table", [ + ["Long Ringlets", "Your hair is done up in large, long ringlets."], + ["Dumplings", "Your hair is long, with 'dumplings' on top."], + ["Mesh", "You have a mesh haircut, a short, stylish hairdo that's trendy in Japan."], + ["Curly Hair", "Your hair is curly enough to defy gravity, and always takes the same shape."], + ["One Eye Hair", "Your hair hangs down so that it conceals one of your eyes."], + ["Antenna Hair", "Your hair has antennas/feelers and a mind of its own."] + ] + ], + ["Accessory", "You have a special accessory attached to your uniform.\n>> Accessory table", [ + ["Collar", "Your hair has antennas/feelers and a mind of its own."], + ["Large Ribbon", "You wear a large ribbon in your hair."], + ["Spike", "Your maid uniform has spikes attached to it."], + ["Chains", "Your maid uniform has jangling chains attached to it."], + ["Black Leather Gloves", "You normally wear black leather gloves. These can be fingerless or have rivets if you like."], + ["Pet", "You have a cat, snake, raven, or some other small animal as a pet that rests on your shoulder or in your hand."] + ] + ], + ["Relationship or Perversion", "Lighter Game? You have a relationship to another player character (Maid).\n>> Relationship table\nDarker Game? You have a bizarre perversion of some kind.\n>> Perversion table", [ + ["Sibling or Nymphomaniac", "You're related by blood to one of the other characters.\nor\nYou're abnormally interested in physical love. It's up to the players and GM to decide how far you want to, or should, roleplay this."], + ["Childhood Friends or Sadist", "You grew up together in the same neighborhood as one of the other characters, and have been great friends since a very early age.\nor\nYou're excited by causing pain and suffering to others."], + ["Mentor or Masochist", "You look upon one of the characters as a personal mentor, perhaps even as a father/mother figure\nor\nYou're excited by being caused pain and suffering by others."], + ["Friendly Rival or Womanizer", "You and another character are rivals in some area of life, and you always find yourself both consciously or subconsciously competing with, and comparing yourself with, that person. However, you are still friends (at least in appearance).\nor\nYou're only romantically attracted to members of the same sex, which is fine (and perhaps expected)... But in your case, it's turned up to '11'."], + ["Ex-Lover/Love Rival or Likes Them Young", "You used to date another character. Perhaps there are still feelings. Alternately, you both might be seeking the love of a third person.\nor\nYou're only interested in . . . younger partners. You can decide what age range this entails."], + ["Vengeance or Exhibitionist", "Another character wronged you in some way in the past. She may not even realize that she did (and it might not have seemed a big deal). But you will never forget.\nor\nYou enjoy showing off your nude or semi/nude body. 'Inappropriate dress' is not just a word, it's a way of life."] + ] + ], + ["Criminal Tendencies", "You have an inclination towards criminal acts.", [ + ["Killer", "You have a bad habit: killing people."], + ["Pyromaniac", "You love setting fires. You might even set fire to the mansion . . ."], + ["Kleptomaniac", "You can't help but steal things, regardless of whether or not you have any use for them."], + ["Addict", "Whether it's narcotics, stimulants, or just sleeping pills, you're a substance-abuser. If you don't get to have any, you'll experience withdrawal symptoms."], + ["Otaku", "You have some obsession that you tirelessly pursue, with little or no regard for common sense."], + ["Stalker", "You're stalking a particular person. Select the target from among the other PCs or the master."] + ] + ], + ["Injury", "Because of mistreatment or an accident, you have some kind of permanent physical injury.\n>> Injury table", [ + ["Patchwork", "Your body is covered with stitching scars."], + ["One Eye", "You have only one eye. You're free to decide whether you wear an eye patch, and if so its design."], + ["Burns", "Your face, body, etc. are covered with painful-looking scars from burns."], + ["Whip Scars", "Your back and such is covered with painful-looking welts from whippings you received (and may possibly be still receiving?)"], + ["Bandages", "You wear many bandages and casts, concealing injuries that will not heal."], + ["Blind", "You were rendered blind a long time ago. (No particular penalties for this: See the classic Zatoichi movies for reference)."] + ] + ], + ["Tragic Love", "You have had sad or tragic experiences with love.\n>> Tragic love table", [ + ["Separations", "For some reason love just never works out for you. At this point you've resigned yourself to fate."], + ["Lover Died", "You had a lover who died since then you've been afraid to fall in love."], + ["Killed Your Lover", "For whatever reason, you killed your last lover since then you've been afraid to fall in love. Or afraid for the object of your desire."], + ["Former Prostitute", "You used to sell your body, for cheap. A complex remains."], + ["Betrayal", "You were once betrayed by a lover since then you've been afraid to fall in love or let your guard down."], + ["Stalker Damage", "You were once victimized by a stalker. You can't trust members of the opposite sex . . . or maybe the same sex."] + ] + ], + ["Dark Past", "There is something dark in your personal history.\n>> Dark past table", [ + ["Former Delinquent", "Although no one would know it looking at you now, you used to be a delinquent. Fortunately right now there's no one (in the mansion at least) who knows about your past."], + ["Former Killer", "You were once a hired killer. Even now, your skills have not been dulled."], + ["Amnesiac", "You've lost your memories from when you were very young. (The GM should come up with something to reveal during the game)."], + ["Bad Reputation", "You were involved with some bad stuff back in the day, and you have the dubious honor of being a legend for all the wrong reasons."], + ["Wanted", "The police want to question you about a serious crime. The player can decide whether or not the character is actually guilty."], + ["Runaway", "You've left your real home without permission."] + ] + ], + ["Trauma", "After some terrible incident, you were traumatized.\n>> Trauma table", [ + ["Suicide Attempts", "In the past, you attempted suicide many times."], + ["Killed Your Parents", "For whatever reason, you are responsible for the death of your parents."], + ["Saw Parent Die", "You witnessed your parents' (one or both) death with your own eyes."], + ["Sibling Hate", "You and your sister(s) detest each other."], + ["Family Breakup", "For some reason (economic trouble?) your family was forced to break up. You may have even caused it."], + ["Abusive Parents", "You were raised by abusive parents."] + ] + ], + ["Secret Job", "You're not just a maid: you're secretly holding another job.\n>> Secret job table", [ + ["Assassin", "While you put on the facade of being a maid, underneath you're a coldhearted killer for hire."], + ["Hacker", "Aside from being a maid, you're a hacker, breaking into computer systems."], + ["Scientist", "Along with being a maid, you're some kind of mad scientist."], + ["Doctor/Pharmacist", "In addition to being a maid, you have the skills of a doctor or a pharmacist."], + ["Doujin Artist", "In addition to being a maid, you create doujinshi in your spare time. You can decide the genre."], + ["Pro Creator", "Along with being a maid, you're working as a professional creator, craftsperson or artist. You can decide the form and genre of your works."] + ] + ], + ["Membership", "In addition to being a maid, you're also a member of a certain organization.\n>> Membership table", [ + ["Evil Secret Society", "You're a member of an evil secret society that seeks to conquer or destroy the world."], + ["Secret Agency", "You're part of a secret agency under the government or the United Nations, some sort of intelligence agent or spy."], + ["Cult", "You're a member of some kind of eccentric cult, whether as a believer, a leader, or even the founder."], + ["Political Organization", "You're part of a group organized around some kind of political ideal, possibly something extreme to the point of insanity."], + ["Shadow Clan", "You're a member of one of the secret organizations that has existed throughout history. You could be a ninja, a magician, one of the knights templar, a kung fu assassin, etc."], + ["Government Official", "You're actually a government official who is working as a maid, whether because you're a nurse, a detective going undercover, or a politician's secretary."] + ] + ], + ["Shapeshifter", "You are an animal or weapon that has taken the form of a maid.\n>> Shapeshifter table", [ + ["Fox", "You're actually a fox, and can display or hide your ears and tail at will."], + ["Spider", "You're actually a spider, and you can become an actual human-sized spider, or else just grow up to six extra arms at will."], + ["Raven", "You're actually a raven. You have black wings that can be displayed or hidden."], + ["Bunny", "You're actually a bunny, with bunny ears and a tail."], + ["Tiger/Lion", "You're actually a predatory cat, and you have ears, a tail, claws, and sharp teeth than you can display or hide at will."], + ["Snake", "You're actually a snake, and you can take on a naga form, turning the lower half of your body into a snake tail."] + ] + ], + ["Monster", "You're not human, but rather some kind of monster.\n>> Monster table", [ + ["Mermaid", "You're actually a mermaid. You love water, and your ears sometimes look like fins."], + ["Zombie/Mummy", "You're actually an animated corpse. Your complexion is probably bad, and you have conspicuous wounds."], + ["Werewolf", "You're actually a werewolf (or maybe a weretiger). Whether or not you want to, you turn into a wolf (or tiger) during a full moon."], + ["Succubus", "You're actually a succubus, a female demon that traps her prey by arousing their desires. You have some demonic physical traits (you decide the specifics) that can be displayed or hidden."], + ["Ghost", "You're actually a ghost. You might have been one of the master's ancestors, or perhaps a maid who worked at the mansion in the past."], + ["Shinigami", "You're actually a shinigami, a death reaper. As such, you carry with you an aura of death. You might be there to deliver a specific person to the other side, or perhaps your reasons are more mundane."] + ] + ], + ["Magic", "You can use some kind of magical power.\n>> Magic table", [ + ["Priestess", "You can use magic grounded in some kind of religious ceremony. You must use various types of religious symbols to do so."], + ["Onmyouji", "You practice Eastern-style magic based on Taoist principles. Your key item for this is jufu, special curse charms written in brush ink on strips of paper."], + ["Fortuneteller", "Within certain limits, you have the ability to predict the future. There are countless methods of divination."], + ["Western Magician", "You practice alchemy, Kabbalah, or some other form of Western sorcery. As such, you are a staffwielding orthodox magician."], + ["Devil Summoner", "You know the spells necessary to summon demons. Your tools of the trade are magic circles, a black cloak, and ancient books."], + ["Necromancer", "You wield magic that lets you control the souls and bodies of the dead. Your tools of the trade include skulls and black clothes."] + ] + ], + ["Absurd", "You're something that flies in the face of common sense.\n>> Absurd table", [ + ["Alien", "You're an alien who came to our world from somewhere in outer space. Your body can have some special properties if you wish."], + ["Cyborg", "You were turned into a cyborg by an evil secret society or some other country. Your body can have some special features if you wish."], + ["Runaway Ninja", "You ran away from your ninja village."], + ["Magical Girl", "You came from a land of magic in order to train."], + ["Fairy", "You're one of the fae folk. You can be a generic pixie, or something more specific."], + ["Mutant", "You've suffered some kind of strange mutation."] + ] + ] + ], + "powers" : [ + [ + ["Super Evasion", "In exchange for 1d6 Stress, you can completely avoid a single attack."], + ["Iron Wall", "You can use your Athletics attribute to defend up to two other characters."], + ["Trespass", "You can take 1d6 Stress to intrude on a battle, love scene, etc. You can also butt in after the action has ended, and this can even work when someone is using World For Two."], + ["Weapon From Nowhere", "You can pull your weapon out seemingly from nowhere, and get in a surprise attack. If you make a surprise attack, you get to make an attack roll without the target getting to make an opposed roll."], + ["Giant Weapon", "You can attack with a giant weapon. (+1 to Athletics for attacking)."], + ["Ultimate Retort", "You can blow off an opponent completely by delivering a good retort (GM decides). You can make it impossible to defend against this by taking 2 Stress. (This must be role-played)."] + ], + [ + ["Maiden's Tears", "By taking 2D6 Stress, you can make a request that can't be refused. (This must be role-played)."], + ["World for Two", "By taking 1D6 Stress, you can create a 'world' for you and one other person, where for 5 minutes no one else can intrude"], + ["Power of Friendship", "You can take 1D6 Stress in order to remove 2D6 Stress from someone else."], + ["Cooked With Love", "When someone eats food you've prepared, they lose 1D6 Stress."], + ["Windows of the Soul", "You understand the master's feelings better than anyone, and can offer careful help. (Add 2 to Favor gained)."], + ["Passionate Gaze", "With just a glance, you can ingratiate yourself with the master, taking 1D6 Stress to gain 1D3 Favor."] + ], + [ + ["Lock Picking", "You can enter any room whenever you feel like. This works even when someone is using World for Two."], + ["Stalking", "When you're following someone, there's no chance for them to detect you. Don't even bother rolling dice."], + ["Lie Detector", "By taking 1 Stress you can make other players or the master admit if they've lied."], + ["Ultimate Menu", "Add +1 to your Skill for the purposes of cooking."], + ["Instant Cleaning", "Add +1 to your Skill for the purposes of doing cleaning."], + ["4-D Dress", "You can produce anything in the mansion from within your maid uniform."] + ], + [ + ["Punishment", "When other maids make mistakes, you can gain the right to punish them, without them having a chance to make an opposed roll."], + ["Instant Restraint", "If you win a roll of Cunning Vs. Athletics, you can restrain someone from doing something indecent."], + ["Coercion", "If you win a roll of Cunning Vs. Athletics, you can completely damage or tear off someone's clothes, even 'accidentally'."], + ["Trap", "Even if you aren't there at the time, you can have a trap prepared in advance during a battle."], + ["Fake Crying", "You can use fake frying to use your Cunning for what would normally be an Affection roll. (This must be role-played)."], + ["Mockery", "When someone is taking Stress points, you can mock them and cause them to gain an additional 2 Stress points. (This must be roleplayed)."] + ], + [ + ["Karma", "You can use your Luck to dodge an attack, and if you roll a 10 or higher you cause twice as much Stress to the opponent."], + ["Saw It", "You can declare that you've seen something happening in the mansion; you can decide the timing too."], + ["Teleport", "You can go just about anywhere in the mansion instantly."], + ["Escape", "You can completely flee from a battle without taking any Stress."], + ["Foreboding", "You can tell when something dangerous is coming."], + ["Chance Meeting", "By taking 2 points of Stress, you can have an NPC that's just showing up for the first time be an acquaintance from some time before."] + ], + [ + ["Immune to Pain", "During a battle, even if you're sent flying, you don't take any Stress. Outside of battle, however, you can still take Stress points like usual."], + ["Crisis Adrenaline", "You can spend 1D6 points of Favor to add an Athletics roll to your Stress. You cannot use this to deliberately avoid the natural removal of Stress points."], + ["Persistence", "Whenever you take Stress, automatically reduce the amount by 1"], + ["Tenacity", "Even after being defeated in battle, you can take 2 Stress to get to your feet."], + ["Hard Work", "Your relentless hard work pays off in the form of a +3 bonus to the end result (not the attribute or die roll) of Skill rolls."], + ["Absolute Maid", "You are the very epitome of a maid, and you take no penalties when not in full uniform."] + ] + ], + "roots": [ + ["Debts", "Your family wound up with massive debts, and you found yourself coming to work at the mansion as repayment."], + ["Slave", "You are a slave, and have no choice about your line of work."], + ["Mistress", "Although you appear to be a maid, it would be more accurate to call you the master's lover."], + ["Revenge", "The master is your hated enemy, and you are infiltrating his mansion in order to extract revenge."], + ["Orphan", "You are an orphan adopted by the master or his parents."], + ["Illegitimate Child", "You are an illegitimate child. From a legal standpoint you're no different from the master."], + ["Hereditary Maid", "You were born into a family that has served the mansion for generations."], + ["Self Punishment", "In order to punish yourself for your inexperience or sins, you have taken up the job of a maid."], + ["Unrequited Love", "Following your one-sided love of the master, you have come here."], + ["Business", "You are a maid because you want the wages. And that's about it."], + ["Infiltrator", "You are a member of an organization that opposes the master, and you have been sent to spy on or possibly even assassinate him."], + ["Loyalty", "You feel great loyalty to the master."], + ["Childhood Friend", "As the master's childhood friend, you've used your influence to get here."], + ["Admirer of Maids", "You have long admired maids, and through much hard work you've finally become one yourself."], + ["Returning a Favor", "The master did a great service to you, and you have become a maid in order to repay him."], + ["Distant Relative", "Although you are only distantly related to the master, your parents have put you in his care."], + ["Bridal Training", "You became a maid in order to prepare yourself to become an ideal bride some day."], + ["Who Knows?", "You're really not quite sure how you wound up becoming a maid."] + ] + }, + + "butler" : { + "colors" : { + "suit" : ["Black", "Light Gray", "Dark Gray", "Dark Blue", "White"], + "hair" : ["Black", "Gray", "Blonde", "Silver", "White"] + }, + "weapons" : [ + ["Striking Martial Arts", "You use Karate, Boxing, Muay Thai, Kung Fu, Capoeira or some other striking martial art to attack."], + ["Grappling Martial Arts", "You use Jujutsu, Aikido, Judo, or some other grappling/joint locking martial art to attack."], + ["Security", "You can use the traps and other security devices installed all throughout the mansion to attack."], + ["Tank", "You use your favorite tank to blast or run over your enemies."], + ["Combat Helicopter", "You use your favorite combat helicopter to shoot or bombard your enemies."], + ["Torture Implements", "Torture implements that are awful just to look at. Fingernail pullers, the iron maiden, finger crushers, etc."], + ["Handgun", "A revolver, derringer, automatic pistol, or other handgun."], + ["Machinegun", "A machinegun that can throw out a rain of bullets in a short period of time."], + ["Rifle", "An assault rifle, shotgun, musket, etc."], + ["Bomb/Grenade", "You use bombs, grenades, or maybe plastic explosives."], + ["Bazooka", "When a fight breaks out you pull out a big-ass bazooka."], + ["Ray Gun", "It might look like a prop of a 50s sci-fi B movie, but the ray gun you're packing really does hurt people."], + ["Devil Power", "Your physical body, fused with a demon, is a weapon in itself. You use this overwhelming, superhuman power to crush your foes. How it works exactly is up to you."], + ["Hammer", "You wield a hammer, whether a small throwing hammer, a big warhammer, or one of the squeaky toy variety."], + ["Scythe", "You wield a big scythe worthy of the Grim Reaper."], + ["Kung Fu Weapon", "Nunchucks, Three-Section Staff, Tonfa, Sai, Tai Chi Sword, etc."], + ["Chainsaw", "Never mind how loud it is you fight with a chainsaw!"], + ["Wooden Sword/Staff", "You wield bokken - Japanese-style wooden sword - or a staff."], + ["Axe/Hatchet", "A tomahawk, battle axe, halberd, etc."], + ["Morningstar", "Basically a mace with spikes. You can have a flail instead if you like."], + ["Western Sword", "A long sword, rapier, flamberge, two-handed sword, etc., etc."], + ["Whip", "A normal whip, a cat of nine tails, a metal whip, etc."], + ["Spear/Lance", "A spear, lance, javelin, etc."], + ["Exotic Weapon", "A boomerang, qatar, African throwing irons, etc."], + ["Knife/Scalpel", "You attack with a knife or scalpel. You can throw it too, and it can be a large dagger if you like."], + ["Chain/Rope", "You attack with a chain or rope."], + ["Claws", "You attack with claws, a bagh nakh, cestus, or some other claw-like weapon."], + ["Katana", "You wield a katana, or possibly a kusarigama or some other traditional Japanese weapon."], + ["Beam Attack", "You can fire a destructive beam of light, heat, cold, or electricity from your hands or eyes. This is not a power possessed by human beings."], + ["Fire", "You can spew fire from your hands or mouth. This makes it kind of hard to believe that you're human."], + ["Summoning", "You are able to summon some kind of special being to attack. You can decide what you summon and how it attacks."], + ["Magic", "You use magic to attack. Or at least something that we might as well call magic."], + ["Psychic Powers", "Well, you have some kind of psychic/super power that you use to attack. You can decide the details."], + ["Book", "You wield a book as a blunt instrument, and possibly tear out pages, to attack."], + ["Internal Weapons", "You have some kind of weapons installed in your body."], + ["Religious Symbol", "You can use a cross, prayer wheel, paper charm, or other seemingly harmless religious symbol to deliver attacks."] + ], + "types" : [ + ["Shadow", "Ninja, Phantom, Escort, Surveillance Expert, Enforcer", [1, 0, 0, 0, 0, 0], "Athletics +1"], + ["Elite", "Expert, Right-Hand Man, Trusted Friend, Cynic, Inspector, Wicked Tongue", [0, 0, 0, 1, 0, 0], "Cunning +1"], + ["Monster", "Inhuman Strength, Unworldly, Monster, Beast", [1, 0, 0, 0, 0, 0], "Athletics +1"], + ["Partner", "Companion, Friend, Adviser, Unbreakable Bond", [0, 1, 0, 0, 0, 0], "Affection +1"], + ["Gothic", "Servant, Austere, Mechanical, Educator, Manager", [0, 0, 1, 0, 0, 0], "Skill +1"], + ["Veteran", "Expert, Old Hand, Coach, All-Purpose", [0, 0, 0, 0, 0, 0], "Any One Attribute +1\n(Raise this attribute manually!)"] + ], + "qualities" : [ + ["Glasses", "You wear glasses, and can't use contact lenses. The frame design can be whatever you want, and this can include a monocle."], + ["Sunglasses", "You always wear sunglasses or mirrorshades. As a rule, you don't take these off."], + ["Furrowed Brows", "Your brows are always furrowed, like you're in a bad mood."], + ["Quiet", "Strangely different from the 'Cool' Maid Type. No, there are no rules regarding how often you speak."], + ["My Pace", "You like to live life at your own particular tempo, and you're always calm and laid-back. This does not affect your attributes."], + ["Shibui", "Most butlers are well-kept and affable gentleman. But you are beyond that. Think Sean Connery on his best days."], + ["Brown Skin", "Your skin is a dark brown color, either naturally or because of tanning."], + ["Narrow Eyes", "You have narrow eyes. They make it look like you're smiling. What you're really feeling is another matter entirely."], + ["Knight Talk", "You speak like a knight of old, saying 'thou art' and such a lot."], + ["A Woman", "You're actually a woman dressed as a man. Or you could be a hermaphrodite or something. You may roll for your other Special Qualities on the maids' Special Quality table if you wish."], + ["Giant", "You're huge, more than two meters tall."], + ["Muscular", "Your body is like a work of art, shrouded as it is in an armor of muscle."], + ["Attractive", "One or more of the maids finds you attractive, if a little unapproachable because of your position."], + ["Misshapen Body", "Some part of your body has suffered damage or is otherwise abnormal. You might have one arm, a strangely bent arm, or otherwise be misshapen."], + ["Android", "You're not human, but rather a human-looking robot. Parts of your body are very obviously artificial."], + ["Vampire", "You are a vampire, with long fangs. Be sure to act... vampiric."], + ["White Eyes", "Your eyes are almost completely white and have no pupils. Or, your eyes might always be glowing."], + ["Emaciated", "You have long, thin limbs and an emaciated body. Your figure reminds people of a spider or a wire frame."], + ["Bishonen", "Not only are you attractive, but women - and men - adore you. There's a good chance that you're also romantically attracted to members of the same sex."], + ["Sadist", "You're excited by causing pain and suffering to others."], + ["Sibling", "You have a relationship with one of the other Maids: You are siblings."], + ["Sportsman", "Pick a sport. You are a legend at playing it. The more elegant the sport, the better (fencing, polo, cricket, etc)"], + ["Patchwork", "Your body is covered with stitching scars."], + ["One Eye", "You have only one eye. You're free to decide whether you wear an eye patch, and if so its design."], + ["Burns", "Your face, body, etc. are covered with painful-looking scars from burns."], + ["Masochist", "You're excited by being caused pain and suffering by others."], + ["Former Mercenary", "You were once a mercenary, constantly moving from battlefield to battlefield. You haven't forgotten any of your experiences or instincts from that time."], + ["Amnesiac", "You've lost your memories from when you were very young. (The GM should come up with something to reveal during the game)."], + ["Wanted", "The police want to question you about a serious crime. The player can decide whether the character is actually guilty."], + ["Secretly an Assassin", "While you put on the facade of being a butler, underneath you're a coldhearted killer on the side."], + ["Hacker", "Aside from being a butler, you're a hacker, breaking into computer systems."], + ["Doctor", "In addition to being a butler, you have the skills of a doctor or a pharmacist."], + ["Shadow Clan", "You're a member of one of the secret organizations that has existed throughout history. You could be a ninja, a magician, one of the knights templar, a kung fu assassin, etc."], + ["Mummy", "You're actually an animated corpse. Your complexion is bad, and you have conspicuous wounds."], + ["Priest", "You can use magic grounded in some kind of religious ceremony. You must use various types of religious symbols to do so."], + ["Cyborg", "You were made into a cyborg by an evil secret society or another country. You can have some special features if you wish."] + ], + "powers" : [ + [ + ["Super Evasion", "In exchange for 1d6 Stress, you can completely avoid a single attack."], + ["Lock Picking", "You can enter any room whenever you feel like. This works even when someone is using World for Two."], + ["Stalking", "When you're following someone, they won't spot you at all. (No roll possible)."], + ["Surprise Attack", "In a flash you can bring out a weapon and deliver an attack. (Add +10 to the result for the first attack during combat, using a weapon)."], + ["Saw It", "You can declare that you've seen something happening in the mansion; you can decide the timing too."], + ["Now You See Him...", "You don't need to actually move around the mansion to get where you need to be, as you can simply appear where you like within the house."] + ], + [ + ["Support", "By spending 1D6 Favor, you can modify someone else's die roll by +1 or -1."], + ["Intrigue", "This butler can make rolls to resist the actions of maids, but only when the Master isn't there to see."], + ["Knowing Laugh", "When the maids cause disruptions during your work (not including Seduction rolls), you can automatically succeed at ignoring them."], + ["Insight", "With nothing more than an intent look you can make someone of the opposite sex (or maybe the same sex) feel enough feelings of love that they won't choose to attack."], + ["Trap", "Even if you aren't there at the time, you can have a trap prepared in advance during a battle."], + ["Futile", "You can prevent an opponent from using any special powers or Favor points they might possess."] + ], + [ + ["Person Inside", "You actually have a maid inside of you somehow. You have the option of re-creating your character as a maid and participating in the game that way whenever you wish."], + ["Fighting Spirit", "You have a powerful aura that extends for about 5 meters in every direction, and this gives you a bonus of +1 to die rolls for fighting any non-butler opponents."], + ["Eerie", "Because of your eerie appearance and atmosphere, you can apply a -1 penalty to rolls made to resist you by members of the opposite sex."], + ["Limiter", "Usable for attacks made using Athletics. You can make two attacks against opponents within your field of vision, but you take 10 Stress for each attack."], + ["Giant Weapon", "You can attack with a giant weapon. (+1 to Athletics for attacking)."], + ["Berserker", "When making an attack using Athletics, you can opt to an all-out attack that encompasses friends and foes alike, and adds +1 to the die roll."] + ], + [ + ["Backup", "When a maid has failed and is about to lose Favor points, you can back her up and prevent her from losing Favor."], + ["World for Two", "By taking 1D6 Stress, you can create a 'world' for you and one other person, where for 5 minutes no one else can intrude."], + ["Twisted Love", "Because of your twisted love for the Master, every time you gain Favor from the Master, you also reduce your Stress by the same amount."], + ["Deep Trust", "Because of your deep bond of trust with the Master, each time you gain Favor from the Master you receive an additional 2 Favor."], + ["Bonds of the Heart", "You understand the Master's feelings better than anyone, and as such you can give him sensible assistance (+2 points of Favor gained)."], + ["Two As One", "When the Master is in danger or has taken Stress, you can take the Stress yourself and instantly arrive at his location."] + ], + [ + ["Punishment", "When maids make mistakes, you can gain the right to punish them, without them having a chance to make an opposed roll."], + ["Lie Detector", "By taking 1 Stress you can make other players or the master admit if they've lied."], + ["Old Hand", "Whether a Special Quality or a weapon, you can declare that you're conversant in skills that you haven't been shown to possess before."], + ["As Expected", "You can spend 2 points of Favor to automatically succeed at resisting with Luck. (Treat this as getting the same result as the opponent)."], + ["Foreboding", "You can act as though you had knowledge of impending danger (especially Random Events) before the fact."], + ["Consequences", "You can spend 3 Favor to re-roll the die for any action you take."] + ], + [ + ["Invincible", "You take no Stress from attacks made with Attributes of 2 or less."], + ["Crisis Adrenaline", "You can spend 1D6 points of Favor to add an Athletics roll to your Stress. You cannot use this to deliberately avoid the natural removal of Stress points."], + ["Connections", "You have whatever kinds of special connections you want. You can request the assistance of other groups or organizations from outside of the mansion."], + ["Chance Meeting", "By taking 2 points of Stress, you can have an NPC who just appeared be someone you knew previously, and decide the nature of that relationship."], + ["Manly Tears", "By taking 2D6 Stress, you can make requests of others (PCs or NPCs). This must be role-played."], + ["Meatshield", "You can shield others, taking the Stress points that would've been applied to up to two others within your field of vision."] + ] + ], + "roots" : [ + ["Hatred", "His dark hatred will not be satisfied by mere violence, and he lies in wait to bring true despair to bear."], + ["Ambition", "His desire stirs him. He conceals your sharp fangs beneath a mask of subservience, until the day when he's ready to take everything that belongs to the Master."], + ["Contract", "He works in the mansion simply as part of a clear-cut employment contract. At the very least, the pay isn't bad."], + ["Affection", "He feels deep affection for the Master, the maids, and even the mansion itself. He sees them as difficult children he loves so much he can't help but tend to them."], + ["Loyalty", "He serves the mansion as a shield, and his loyalty is absolute. He will do anything for the master of the house, even at the cost of his own life."], + ["Family", "He can be thought of as the Master's family. They both need each other, and the division between Master and servant is not so obvious."] + ] + }, + + "master" : { + "types" : [ + ["Small Child", "The Master is a small child. At this age most know nothing of the outside world and have no trace of suspicion.", "2D6"], + ["Legitimate Child", "The Master is still a child. He's just starting to understand his power.", "5+2D6"], + ["Layman", "The Master is an ordinary person who came into wealth by chance.", "8+2D6"], + ["Natural Born", "The Master is a young man or woman, and probably learned certain things wrong and has some twisted ideas.", "12+2D6"], + ["Aristocrat", "This person was born to be the master of the house. Regardless of age, he has excellent self-control.", "1D66"], + ["Recluse", "The Master has already put an end to his dealings with the outside world, and adopted a secluded lifestyle.", "1D66+10"] + ], + "qualities" : [ + ["Glasses", "You wear glasses, and can't use contact lenses. The frame design can be whatever you want, and this can include a monocle."], + ["Sickly", "You've got an incurable disease. However, this doesn't adversely affect your attributes."], + ["Royalty", "You're among the heads of a country or organization, and as a result your life is often put in danger."], + ["Quiet", "Strangely different from the 'Cool'', Maid Type. No, there are no rules regarding how often you speak."], + ["My Pace", "You like to live life at your own particular tempo, and you're always calm and laid-back. This does not affect your attributes."], + ["OCD", "You're obsessed with hygiene management. You can't let the slighted bit of dirt pass."], + ["Brown Skin", "Your skin is a dark brown color, either naturally or because of tanning."], + ["Albino", "You have no pigment. You're not necessarily completely colorless, and this can simply be a very pale complexion."], + ["Shy", "You're very shy. Don't forget to remain silent when encountering NPCs you haven't met before."], + ["Cross-Dresser", "You outwardly appear to be of the opposite sex, which gives you a kind of perverse allure."], + ["Imagination", "You frequently get caught up in your own imaginary world."], + ["Hermaphrodite", "You're both male and female. The player can decide which is the base sex."], + ["Bishounen/Bishoujo", "Not only are you attractive, but women - and men - adore you. There's a good chance that you're also romantically attracted to members of the same sex."], + ["Noble Hair", "Your hair is done up in long rolls, your beard is very aristocratic, or you otherwise have hair that your position amongst nobility. clear"], + ["Hedonist", "You only care about being able to passively enjoy life, or to put it nicely, you have no prejudices to speak of."], + ["Vampire", "You are a vampire, with long fangs. Be sure to act... vampiric."], + ["Otaku", "You have some obsession that you tirelessly pursue, with little or no regard for common sense."], + ["Angel/Devil", "You are a being from another world charged with judging good and evil. The design and the details of your origins are up to you."], + ["Lecherous", "Sexual harassment isn't just a crime, it's a way of life."], + ["Sadist", "You're excited by causing pain and suffering to others."], + ["Masochist", "You're excited by being caused pain and suffering by others."], + ["Handicapped", "You can only move around on your own with a wheelchair, or you might even outright be confined to your bed."], + ["Scars", "Your face, back, etc. are covered with painful-looking scars."], + ["Kidnapped", "You were once kidnapped and held for 1D6 days. Even today it remains a scar in your heart."], + ["Capable Sibling", "You have a sibling who excels at seemingly everything. You're tormented by an inferiority complex."], + ["Family Hate", "You despise one or more of your parents or siblings. The GM can decide what if anything happened in the past."], + ["Professional Criminal", "You're a professional criminal, and most of your assets no doubt came from ill-gotten gains."], + ["Amnesiac", "You've lost your memories from when you were very young. (The GM should come up with something to reveal during the game)."], + ["Artist", "You are a musician, painter, writer, actor, singer, composer, or some other kind of highly talented artist."], + ["Evil Emperor", "You are the leader of an evil kingdom or secret society, or the leader of a group aimed at tearing down society."], + ["Undead", "Despite your rotting body, you live on. This can be a mummy, zombie, lich, etc."], + ["Scientist", "You are a scientist who freely commands advanced technology, and who dabbled in countless fields."], + ["Oracle", "You can predict the future to a certain degree. There are any number of possible ways this can be carried out, and the player is free to define how their character does so."], + ["Magician", "You wield sorcerous powers, in the matter of a typical fantasy wizard."], + ["Priest", "You are a priest of some religion or other."], + ["Maid Quality", "Roll 1D66 and re-roll the tens digit if it's less than 4, so you get a result from 41-66 from the Maid Special Quality table.\n>> Maid quality table"] + ], + "powers" : [ + ["None", "You don't seem to have any power at all. (During the game, the player can roll 2D6 and replace 'None' with some other Power Source)."], + ["Fear", "You are a tyrannical despot who rules by fear, or you have channels through the underworld. You have many enemies, and little time to rest easy."], + ["Magical Power", "Power. Magic. Something beyond the pale. You possess this, and through it your very existence demands special treatment."], + ["Blood Ties", "Regardless of what real power you might have, your heritage demands special treatment."], + ["Military Might", "You posses military might, such that no one around you would dare oppose you."], + ["Assets", "It is the fortune you've amassed that gives you your power."], + ["Political Power", "As the leader of an organization you have the power to command many people."], + ["Mansion", "The true value lies not in you yourself, but in the mansion where you live. Perhaps some unimaginable technology or wealth sleeps there."], + ["Talent", "You have a great talent in some particular area, or perhaps you're an all-around genius. Your prowess here is such that all must prostrate themselves before you."], + ["Renown", "You are respected by all. You might a great hero, an enemy of all things evil."], + ["Popularity", "You have something that people find irresistible, something worthy of a king. That is why the maids serve you."] + ], + "traumas" : [ "Former delinquent", "Former juvenile vagrant", "Former prostitute", "Social stigma", "Knows no love", + "In love with brother/cousin", "Broken by training", "Miscarriage", "History of suicide attempts", + "Horrible accident (car, fall, etc)", "Kidnapped", "Assaulted", "Mistreated by parents", "Arrested on false charges", + "Targeted by a stalker", "Betrayed by close friend", "Killed a close friend", "Betrayed a close friend", + "Parents disappeared", "Witnessed parents' death", "Parents tried to kill you", "Attacked by parents", + "Ran away from home", "Killed your parents", "Bad unrequited love", "Lover died", "Lover tried to kill you", + "Betrayed by lover", "Killed your lover", "Major failure", "Family breakup", "Took part in something bad", + "Wanted by the police", "Burdened by strong regret", "Destroyed your homeland", "Killed many people" + ] + } +} \ No newline at end of file diff --git a/resources/ram.png b/resources/ram.png new file mode 100644 index 0000000..82e3bc0 Binary files /dev/null and b/resources/ram.png differ diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..b82e052 --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +python -m src diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/__main__.py b/src/__main__.py new file mode 100644 index 0000000..e641672 --- /dev/null +++ b/src/__main__.py @@ -0,0 +1,124 @@ +""" +Maid RPG character generator +'maid' by Wazul + +2017.06.08. +""" +import sys +from PyQt5 import QtWidgets, QtGui, QtCore, Qt +from .modules.maidWidget import CMaidWidget +from .modules.helpWidget import CHelpWidget +from .modules.masterWidget import CMasterWidget +from .modules.butlerWidget import CButlerWidget +from .modules.data_reader import MaidDataReader + +class ApplicationWindow(QtWidgets.QMainWindow): + """ Main window for the application. """ + def __init__(self, data_reader): + QtWidgets.QMainWindow.__init__(self) + self.setAttribute(QtCore.Qt.WA_DeleteOnClose) + self.setWindowTitle('RMG - MaidRPG random generator') + + self.icon = QtGui.QIcon('icon.ico') + self.setWindowIcon(self.icon) + + self.setTabPosition(QtCore.Qt.TopDockWidgetArea, QtWidgets.QTabWidget.North) + + # self.setFixedWidth(550) + # self.setFixedHeight(650) + + self.statusbarMessage = QtWidgets.QLabel("Version number 1.1 - 'maid' by Wazul (2017)") + self.statusBar().addWidget(self.statusbarMessage) + + + self.maidDock = QtWidgets.QDockWidget('Random maid') + self.maidDock.parent = self + + self.maidDock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) + titleWidget = QtWidgets.QWidget() + self.maidDock.setTitleBarWidget(titleWidget) + + self.maidWidget = CMaidWidget(data_reader, self.maidDock) + self.maidDock.setWidget(self.maidWidget) + self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.maidDock) + + + self.butlerDock = QtWidgets.QDockWidget('Random butler') + self.butlerDock.parent = self + + self.butlerDock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) + titleWidget = QtWidgets.QWidget() + self.butlerDock.setTitleBarWidget(titleWidget) + + self.butlerWidget = CButlerWidget(data_reader, self.butlerDock) + self.butlerDock.setWidget(self.butlerWidget) + self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.butlerDock) + + + self.masterDock = QtWidgets.QDockWidget('Random master') + self.masterDock.parent = self + + self.masterDock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) + titleWidgetMaster = QtWidgets.QWidget() + self.masterDock.setTitleBarWidget(titleWidgetMaster) + + self.masterWidget = CMasterWidget(data_reader, self.masterDock) + self.masterDock.setWidget(self.masterWidget) + self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.masterDock) + + + self.helpDock = QtWidgets.QDockWidget('Help') + self.helpDock.parent = self + + self.helpDock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) + titleWidgetHelp = QtWidgets.QWidget() + self.helpDock.setTitleBarWidget(titleWidgetHelp) + + self.helpWidget = CHelpWidget(self.helpDock) + self.helpDock.setWidget(self.helpWidget) + self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.helpDock) + + + self.tabifyDockWidget(self.maidDock, self.butlerDock) + self.tabifyDockWidget(self.butlerDock, self.masterDock) + self.tabifyDockWidget(self.masterDock, self.helpDock) + self.maidDock.raise_() + self.seq = 0 + + def keyPressEvent(self, event): + if self.seq == 0 and event.key() == QtCore.Qt.Key_Up: + self.seq += 1 + elif self.seq == 1 and event.key() == QtCore.Qt.Key_Up: + self.seq += 1 + self.helpDock.setFocus() + elif self.seq == 2 and event.key() == QtCore.Qt.Key_Down: + self.seq += 1 + elif self.seq == 3 and event.key() == QtCore.Qt.Key_Down: + self.seq += 1 + elif self.seq == 4 and event.key() == QtCore.Qt.Key_Left: + self.seq += 1 + elif self.seq == 5 and event.key() == QtCore.Qt.Key_Right: + self.seq += 1 + elif self.seq == 6 and event.key() == QtCore.Qt.Key_Left: + self.seq += 1 + elif self.seq == 7 and event.key() == QtCore.Qt.Key_Right: + self.seq += 1 + elif self.seq == 8 and event.key() == QtCore.Qt.Key_B: + self.seq += 1 + elif self.seq == 9 and event.key() == QtCore.Qt.Key_A: + self.helpWidget.easterEgg() + else: + self.seq = 0 + + +def main(argv): + data_reader = MaidDataReader() + qt_args = [argv[0], '-style', 'Fusion'] + argv[1:] + app = QtWidgets.QApplication(qt_args) + main_window = ApplicationWindow(data_reader) + main_window.show() + sys.exit(app.exec_()) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/modules/__init__.py b/src/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/butlerWidget.py b/src/modules/butlerWidget.py new file mode 100644 index 0000000..c941745 --- /dev/null +++ b/src/modules/butlerWidget.py @@ -0,0 +1,715 @@ +""" +Widget for the random maid dock. +""" + +from random import randint +from math import floor +from PyQt5 import QtWidgets, QtCore + + +class CButlerWidget(QtWidgets.QWidget): + + def __init__(self, data_reader, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.data_reader = data_reader + self.parent = parent + + self.stats = [0, 0, 0, 0, 0, 0] + + self.loVLayoutMain = QtWidgets.QVBoxLayout() + self.loHLayoutMain = QtWidgets.QHBoxLayout() + + self.gbBasic = QtWidgets.QGroupBox('Basics', self) + self.loGbBasic = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Name: ') + hLayout.addWidget(textLabel) + self.liName = QtWidgets.QLineEdit() + self.liName.setFixedWidth(200) + hLayout.addWidget(self.liName) + hLayout.addStretch(1) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Age: ') + hLayout.addWidget(textLabel) + self.liAge = QtWidgets.QSpinBox() + self.liAge.setFixedWidth(50) + self.liAge.setMaximum(9999) + hLayout.addWidget(self.liAge) + self.bAge = QtWidgets.QPushButton('R') + self.bAge.parent = self.liAge + self.bAge.setFixedWidth(50) + hLayout.addWidget(self.bAge) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Suit color: ') + hLayout.addWidget(textLabel) + self.liUniColor = QtWidgets.QLineEdit() + self.liUniColor.setFixedWidth(150) + hLayout.addWidget(self.liUniColor) + self.bUniColor = QtWidgets.QPushButton('R') + self.bUniColor.parent = self.liUniColor + self.bUniColor.setFixedWidth(50) + hLayout.addWidget(self.bUniColor) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Hair color: ') + hLayout.addWidget(textLabel) + self.liHairColor = QtWidgets.QLineEdit() + self.liHairColor.setFixedWidth(150) + hLayout.addWidget(self.liHairColor) + self.bHairColor = QtWidgets.QPushButton('R') + self.bHairColor.setFixedWidth(50) + self.bHairColor.parent = self.liHairColor + hLayout.addWidget(self.bHairColor) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Eye color: ') + hLayout.addWidget(textLabel) + self.liEyeColor = QtWidgets.QLineEdit() + self.liEyeColor.setFixedWidth(150) + hLayout.addWidget(self.liEyeColor) + self.bEyeColor = QtWidgets.QPushButton('R') + self.bEyeColor.setFixedWidth(50) + self.bEyeColor.parent = self.liEyeColor + hLayout.addWidget(self.bEyeColor) + self.loGbBasic.addLayout(hLayout) + self.gbBasic.setLayout(self.loGbBasic) + self.loH1 = QtWidgets.QHBoxLayout() + self.loH1.addWidget(self.gbBasic) + self.gbMaidType = QtWidgets.QGroupBox('Butler Type', self) + self.loGbMaidType = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('First: ') + hLayout.addWidget(textLabel) + self.liFirstType = QtWidgets.QComboBox() + self.setButlerTypeComboBox(self.liFirstType) + self.liFirstType.setFixedWidth(100) + hLayout.addWidget(self.liFirstType) + self.bFirstType = QtWidgets.QPushButton('R') + self.bFirstType.setFixedWidth(50) + self.bFirstType.parent = self.liFirstType + hLayout.addWidget(self.bFirstType) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.descFirst = QtWidgets.QLabel('') + self.descFirst.setWordWrap(True) + self.liFirstType.desc = self.descFirst + self.liFirstType.changeList = [0, 0, 0, 0, 0, 0] + hLayout.addWidget(self.descFirst) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Second: ') + hLayout.addWidget(textLabel) + self.liSecondType = QtWidgets.QComboBox() + self.setButlerTypeComboBox(self.liSecondType) + self.liSecondType.setFixedWidth(100) + hLayout.addWidget(self.liSecondType) + self.bSecondType = QtWidgets.QPushButton('R') + self.bSecondType.setFixedWidth(50) + self.bSecondType.parent = self.liSecondType + hLayout.addWidget(self.bSecondType) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.descSecond = QtWidgets.QLabel('') + self.descSecond.setWordWrap(True) + self.liSecondType.desc = self.descSecond + self.liSecondType.changeList = [0, 0, 0, 0, 0, 0] + hLayout.addWidget(self.descSecond) + self.loGbMaidType.addLayout(hLayout) + self.gbMaidType.setLayout(self.loGbMaidType) + self.gbMaidType.setFixedWidth(220) + self.loH1.addWidget(self.gbMaidType) + self.gbAttri = QtWidgets.QGroupBox('Attributes', self) + self.loGbAttri = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('ATH:') + textLabel.setToolTip('Athletics: Physical ability, combat ability.') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liATH = QtWidgets.QSpinBox() + self.liATH.setFixedWidth(35) + hLayout.addWidget(self.liATH, 1, QtCore.Qt.AlignRight) + self.textATH = QtWidgets.QLabel('(0)') + self.liATH.sumVal = self.textATH + hLayout.addWidget(self.textATH, 1, QtCore.Qt.AlignRight) + self.bATH = QtWidgets.QPushButton('R') + self.bATH.setFixedWidth(50) + self.bATH.parent = self.liATH + hLayout.addWidget(self.bATH, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('AFF:') + textLabel.setToolTip('Affection: How good are you at forming bonds with your master and the other maids?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liAFF = QtWidgets.QSpinBox() + self.liAFF.setFixedWidth(35) + hLayout.addWidget(self.liAFF, 1, QtCore.Qt.AlignRight) + self.textAFF = QtWidgets.QLabel('(0)') + self.liAFF.sumVal = self.textAFF + hLayout.addWidget(self.textAFF, 1, QtCore.Qt.AlignRight) + self.bAFF = QtWidgets.QPushButton('R') + self.bAFF.setFixedWidth(50) + self.bAFF.parent = self.liAFF + hLayout.addWidget(self.bAFF, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('SKI:') + textLabel.setToolTip('Skill: How good are you at your maid duties?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liSKI = QtWidgets.QSpinBox() + self.liSKI.setFixedWidth(35) + hLayout.addWidget(self.liSKI, 1, QtCore.Qt.AlignRight) + self.textSKI = QtWidgets.QLabel('(0)') + self.liSKI.sumVal = self.textSKI + hLayout.addWidget(self.textSKI, 1, QtCore.Qt.AlignRight) + self.bSKI = QtWidgets.QPushButton('R') + self.bSKI.setFixedWidth(50) + self.bSKI.parent = self.liSKI + hLayout.addWidget(self.bSKI, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('CNN:') + textLabel.setToolTip( + 'Cunning: How capable are you at tricking enemies and other maids, and deceiving the master?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liCNN = QtWidgets.QSpinBox() + self.liCNN.setFixedWidth(35) + hLayout.addWidget(self.liCNN, 1, QtCore.Qt.AlignRight) + self.textCNN = QtWidgets.QLabel('(0)') + self.liCNN.sumVal = self.textCNN + hLayout.addWidget(self.textCNN, 1, QtCore.Qt.AlignRight) + self.bCNN = QtWidgets.QPushButton('R') + self.bCNN.setFixedWidth(50) + self.bCNN.parent = self.liCNN + hLayout.addWidget(self.bCNN, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('LCK:') + textLabel.setToolTip('Luck: Just how lucky are you?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liLCK = QtWidgets.QSpinBox() + self.liLCK.setFixedWidth(35) + hLayout.addWidget(self.liLCK, 1, QtCore.Qt.AlignRight) + self.textLCK = QtWidgets.QLabel('(0)') + self.liLCK.sumVal = self.textLCK + hLayout.addWidget(self.textLCK, 1, QtCore.Qt.AlignRight) + self.bLCK = QtWidgets.QPushButton('R') + self.bLCK.setFixedWidth(50) + self.bLCK.parent = self.liLCK + hLayout.addWidget(self.bLCK, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('WIL:') + textLabel.setToolTip('Will: How positive and constructive is your thinking?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liWIL = QtWidgets.QSpinBox() + self.liWIL.setFixedWidth(35) + hLayout.addWidget(self.liWIL, 1, QtCore.Qt.AlignRight) + self.textWIL = QtWidgets.QLabel('(0)') + self.liWIL.sumVal = self.textWIL + hLayout.addWidget(self.textWIL, 1, QtCore.Qt.AlignRight) + self.bWIL = QtWidgets.QPushButton('R') + self.bWIL.setFixedWidth(50) + self.bWIL.parent = self.liWIL + hLayout.addWidget(self.bWIL, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + self.gbAttri.setLayout(self.loGbAttri) + self.loH2 = QtWidgets.QHBoxLayout() + self.loH2.addWidget(self.gbAttri) + self.gbEtc = QtWidgets.QGroupBox('Etcetera', self) + self.loGbEtc = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Butler root: ') + hLayout.addWidget(textLabel) + self.liMaidRoot = QtWidgets.QComboBox() + self.setButlerRootComboBox() + self.liMaidRoot.setFixedWidth(150) + hLayout.addWidget(self.liMaidRoot) + self.bMaidRoot = QtWidgets.QPushButton('R') + self.bMaidRoot.parent = self.liMaidRoot + self.bMaidRoot.setFixedWidth(50) + hLayout.addWidget(self.bMaidRoot) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Butler power: ') + hLayout.addWidget(textLabel) + self.liMP = QtWidgets.QComboBox() + self.liMP.setFixedWidth(150) + self.liFirstType.powerBox = self.liMP + self.liMP.parent = self.liFirstType + hLayout.addWidget(self.liMP) + self.bButlerPower = QtWidgets.QPushButton('R') + self.bButlerPower.parent = self.liMP + self.liMP.rollButton = self.bButlerPower + self.bButlerPower.setFixedWidth(50) + hLayout.addWidget(self.bButlerPower) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Butler power 2: ') + hLayout.addWidget(textLabel) + self.liMP2 = QtWidgets.QComboBox() + self.liMP2.setFixedWidth(150) + self.liSecondType.powerBox = self.liMP2 + self.liMP2.parent = self.liSecondType + hLayout.addWidget(self.liMP2) + self.bButlerPower2 = QtWidgets.QPushButton('R') + self.bButlerPower2.parent = self.liMP2 + self.liMP2.rollButton = self.bButlerPower2 + self.bButlerPower2.setFixedWidth(50) + hLayout.addWidget(self.bButlerPower2) + self.loGbEtc.addLayout(hLayout) + self.liMP.otherMP = self.liMP2 + self.liMP2.otherMP = self.liMP + self.favor = QtWidgets.QLabel('Favor: 0') + self.spirit = QtWidgets.QLabel('Spirit: 0') + self.loGbEtc.addWidget(self.favor) + self.loGbEtc.addWidget(self.spirit) + self.gbEtc.setLayout(self.loGbEtc) + self.loH2.addWidget(self.gbEtc) + self.gbSpec = QtWidgets.QGroupBox('Special Qualities', self) + self.loGbSpec = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec1 = QtWidgets.QComboBox() + self.setButlerQualityComboBox(self.liSpec1) + self.liSpec1.setFixedWidth(150) + hLayout.addWidget(self.liSpec1, 10, QtCore.Qt.AlignRight) + self.bSpec1 = QtWidgets.QPushButton('R') + self.bSpec1.setFixedWidth(50) + self.bSpec1.parent = self.liSpec1 + hLayout.addWidget(self.bSpec1, 0, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec2 = QtWidgets.QComboBox() + self.setButlerQualityComboBox(self.liSpec2) + self.liSpec2.setFixedWidth(150) + hLayout.addWidget(self.liSpec2, 10, QtCore.Qt.AlignRight) + self.bSpec2 = QtWidgets.QPushButton('R') + self.bSpec2.setFixedWidth(50) + self.bSpec2.parent = self.liSpec2 + hLayout.addWidget(self.bSpec2, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec3 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec3, 1, QtCore.Qt.AlignRight) + self.liSpec3 = QtWidgets.QComboBox() + self.setButlerQualityComboBox(self.liSpec3) + self.liSpec3.setFixedWidth(150) + hLayout.addWidget(self.liSpec3, 1, QtCore.Qt.AlignRight) + self.bSpec3 = QtWidgets.QPushButton('R') + self.bSpec3.setFixedWidth(50) + self.bSpec3.parent = self.liSpec3 + self.cbSpec3.button = self.bSpec3 + self.cbSpec3.box = self.liSpec3 + hLayout.addWidget(self.bSpec3, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec4 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec4, 1, QtCore.Qt.AlignRight) + self.liSpec4 = QtWidgets.QComboBox() + self.setButlerQualityComboBox(self.liSpec4) + self.liSpec4.setFixedWidth(150) + hLayout.addWidget(self.liSpec4, 1, QtCore.Qt.AlignRight) + self.bSpec4 = QtWidgets.QPushButton('R') + self.bSpec4.setFixedWidth(50) + self.bSpec4.parent = self.liSpec4 + self.cbSpec4.button = self.bSpec4 + self.cbSpec4.box = self.liSpec4 + hLayout.addWidget(self.bSpec4, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec5 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec5, 1, QtCore.Qt.AlignRight) + self.liSpec5 = QtWidgets.QComboBox() + self.setButlerQualityComboBox(self.liSpec5) + self.liSpec5.setFixedWidth(150) + hLayout.addWidget(self.liSpec5, 1, QtCore.Qt.AlignRight) + self.bSpec5 = QtWidgets.QPushButton('R') + self.bSpec5.setFixedWidth(50) + self.bSpec5.parent = self.liSpec5 + self.cbSpec5.button = self.bSpec5 + self.cbSpec5.box = self.liSpec5 + hLayout.addWidget(self.bSpec5, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + self.gbSpec.setLayout(self.loGbSpec) + self.gbSpec.setFixedWidth(250) + self.loH3 = QtWidgets.QHBoxLayout() + self.loH3.addWidget(self.gbSpec) + self.gbWeap = QtWidgets.QGroupBox('Weapons', self) + self.loGbWeap = QtWidgets.QVBoxLayout() + self.liWeapon = QtWidgets.QComboBox() + self.setButlerWeaponComboBox(self.liWeapon) + self.loGbWeap.addWidget(self.liWeapon) + self.bWeap = QtWidgets.QPushButton('R') + self.bWeap.parent = self.liWeapon + self.loGbWeap.addWidget(self.bWeap) + self.loGbWeap.addWidget(QtWidgets.QLabel('\n\n')) + self.liWeapon2 = QtWidgets.QComboBox() + self.setButlerWeaponComboBox(self.liWeapon2) + self.loGbWeap.addWidget(self.liWeapon2) + self.bWeap2 = QtWidgets.QPushButton('R') + self.bWeap2.parent = self.liWeapon2 + self.loGbWeap.addWidget(self.bWeap2) + self.liWeapon.otherWeapon = self.liWeapon2 + self.liWeapon2.otherWeapon = self.liWeapon + self.gbWeap.setLayout(self.loGbWeap) + self.loH3.addWidget(self.gbWeap) + + self.gbSave = QtWidgets.QGroupBox('Generate and save', self) + self.loGbSave = QtWidgets.QVBoxLayout() + self.bRollAll = QtWidgets.QPushButton('GENERATE\nBUTLER', self) + self.loGbSave.addWidget(self.bRollAll) + self.bSave = QtWidgets.QPushButton('SAVE', self) + self.loGbSave.addWidget(self.bSave) + self.gbSave.setLayout(self.loGbSave) + self.gbSave.setFixedWidth(120) + self.loH3.addWidget(self.gbSave) + + self.loVLayoutMain.addLayout(self.loH1) + self.loVLayoutMain.addLayout(self.loH2) + self.loVLayoutMain.addLayout(self.loH3) + self.loHLayoutMain.addLayout(self.loVLayoutMain) + self.setLayout(self.loHLayoutMain) + + self.setEnabilities() + self.cbSpec3.clicked.connect(self.setEnabilities) + self.cbSpec4.clicked.connect(self.setEnabilities) + self.cbSpec5.clicked.connect(self.setEnabilities) + self.liATH.valueChanged.connect(self.calculateStats) + self.liAFF.valueChanged.connect(self.calculateStats) + self.liSKI.valueChanged.connect(self.calculateStats) + self.liCNN.valueChanged.connect(self.calculateStats) + self.liLCK.valueChanged.connect(self.calculateStats) + self.liWIL.valueChanged.connect(self.calculateStats) + self.bAge.clicked.connect(self.generateAge) + self.bUniColor.clicked.connect(self.generateSuitColor) + self.bHairColor.clicked.connect(self.generateHairColor) + self.bEyeColor.clicked.connect(self.generateEyeColor) + self.bATH.clicked.connect(self.generateAttribute) + self.bAFF.clicked.connect(self.generateAttribute) + self.bSKI.clicked.connect(self.generateAttribute) + self.bCNN.clicked.connect(self.generateAttribute) + self.bLCK.clicked.connect(self.generateLuckAttribute) + self.bWIL.clicked.connect(self.generateWilAttribute) + self.bFirstType.clicked.connect(self.generateButlerType) + self.bSecondType.clicked.connect(self.generateButlerType) + self.bButlerPower.clicked.connect(self.generateButlerPower) + self.bButlerPower2.clicked.connect(self.generateButlerPower) + self.bMaidRoot.clicked.connect(self.generateButlerRoot) + self.bSpec1.clicked.connect(self.generateButlerQuality) + self.bSpec2.clicked.connect(self.generateButlerQuality) + self.bSpec3.clicked.connect(self.generateButlerQuality) + self.bSpec4.clicked.connect(self.generateButlerQuality) + self.bSpec5.clicked.connect(self.generateButlerQuality) + self.bWeap.clicked.connect(self.generateButlerWeapon) + self.bWeap2.clicked.connect(self.generateButlerWeapon) + self.liFirstType.currentIndexChanged.connect(self.changedButlerType) + self.liSecondType.currentIndexChanged.connect(self.changedButlerType) + self.liMP.currentIndexChanged.connect(self.changedButlerPower) + self.liMP2.currentIndexChanged.connect(self.changedButlerPower) + self.liMaidRoot.currentIndexChanged.connect(self.changedButlerRoot) + self.liSpec1.currentIndexChanged.connect(self.changedButlerQuality) + self.liSpec2.currentIndexChanged.connect(self.changedButlerQuality) + self.liSpec3.currentIndexChanged.connect(self.changedButlerQuality) + self.liSpec4.currentIndexChanged.connect(self.changedButlerQuality) + self.liSpec5.currentIndexChanged.connect(self.changedButlerQuality) + self.liWeapon.currentIndexChanged.connect(self.changedButlerWeapon) + self.liWeapon2.currentIndexChanged.connect(self.changedButlerWeapon) + self.bRollAll.clicked.connect(self.generateButler) + self.bSave.clicked.connect(self.saveButler) + + def setEnabilities(self): + for checkb in [self.cbSpec3, self.cbSpec4, self.cbSpec5]: + if not checkb.isChecked(): + checkb.button.setEnabled(False) + checkb.box.setEnabled(False) + checkb.box.setCurrentIndex(-1) + else: + checkb.button.setEnabled(True) + checkb.box.setEnabled(True) + + def generateAge(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled age...', 1500) + i = int(str(randint(1, 6)) + str(randint(1, 6))) + self.liAge.setValue(i) + + def generateSuitColor(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled color...', 1500) + self.liUniColor.setText(self.data_reader.get_butler_random_suit_color()) + + def generateHairColor(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled color...', 1500) + self.liHairColor.setText(self.data_reader.get_butler_random_hair_color()) + + def generateEyeColor(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled color...', 1500) + self.liEyeColor.setText(self.data_reader.get_random_color()) + + def generateAttribute(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled attribute...', 1500) + x = randint(1, 6) + y = randint(1, 6) + retVal = int(floor((x + y) / 2)) + caller.parent.setValue(retVal) + + def generateLuckAttribute(self, hideMessage=False): + if hideMessage == False: + self.parent.parent.statusBar().showMessage('Rolled attribute...', 1500) + x = randint(1, 6) + y = randint(1, 6) + retVal = int(floor((x + y) / 3)) + self.liLCK.setValue(retVal) + + def generateWilAttribute(self, hideMessage=False): + if hideMessage == False: + self.parent.parent.statusBar().showMessage('Rolled attribute...', 1500) + x = randint(1, 6) + y = randint(1, 6) + retVal = x + y + self.liWIL.setValue(retVal) + + def generateButlerType(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled butler type...', 1500) + i = randint(0, 5) + caller.parent.setCurrentIndex(i) + + def generateButlerPower(self, caller=False): + if caller == False: + caller = self.sender() + if caller.parent.count() != 0: + self.parent.parent.statusBar().showMessage('Rolled butler power...', 1500) + if caller.parent.count() != 0: + while True: + i = randint(0, 5) + caller.parent.setCurrentIndex(i) + if caller.parent.otherMP.currentText() == '' or caller.parent.otherMP.currentText() != caller.parent.currentText(): + break + + def generateButlerRoot(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled butler root...', 1500) + i = randint(0, 5) + self.liMaidRoot.setCurrentIndex(i) + + def generateButlerQuality(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled butler special quality...', 1500) + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + + def generateButlerWeapon(self, caller): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled weapon...', 1500) + while True: + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + if caller.parent.otherWeapon.currentText() == '' or caller.parent.otherWeapon.currentText() != caller.parent.currentText(): + break + + def calculateStats(self): + stat0 = self.liATH.value() + self.liFirstType.changeList[0] + self.liSecondType.changeList[0] + stat1 = self.liAFF.value() + self.liFirstType.changeList[1] + self.liSecondType.changeList[1] + stat2 = self.liSKI.value() + self.liFirstType.changeList[2] + self.liSecondType.changeList[2] + stat3 = self.liCNN.value() + self.liFirstType.changeList[3] + self.liSecondType.changeList[3] + stat4 = self.liLCK.value() + self.liFirstType.changeList[4] + self.liSecondType.changeList[4] + stat5 = self.liWIL.value() + self.liFirstType.changeList[5] + self.liSecondType.changeList[5] + self.stats = [stat0, stat1, stat2, stat3, stat4, stat5] + for i in range(len(self.stats)): + if self.stats[i] < 0: + self.stats[i] = 0 + + self.liATH.sumVal.setText('(' + str(self.stats[0]) + ')') + self.liAFF.sumVal.setText('(' + str(self.stats[1]) + ')') + self.liSKI.sumVal.setText('(' + str(self.stats[2]) + ')') + self.liCNN.sumVal.setText('(' + str(self.stats[3]) + ')') + self.liLCK.sumVal.setText('(' + str(self.stats[4]) + ')') + self.liWIL.sumVal.setText('(' + str(self.stats[5]) + ')') + self.favor.setText('Favor: ' + str(self.stats[1] * 2)) + self.spirit.setText('Spirit: ' + str(self.stats[5] * 10)) + + def changedButlerType(self): + comboBox = self.sender() + ii = comboBox.currentIndex() + elem = self.data_reader.data["butler"]["types"][ii] + comboBox.desc.setText(elem[1]) + comboBox.changeList = elem[2] + comboBox.setToolTip(elem[3]) + self.calculateStats() + comboBox.powerBox.setCurrentIndex(-1) + for j in range(6): + comboBox.powerBox.removeItem(0) + + for item in self.data_reader.data["butler"]["powers"][ii]: + comboBox.powerBox.insertItem(100, item[0]) + + comboBox.powerBox.setCurrentIndex(-1) + self.generateButlerPower(comboBox.powerBox.rollButton) + + def changedButlerPower(self): + comboBox = self.sender() + i = comboBox.currentIndex() + j = comboBox.parent.currentIndex() + if not comboBox.currentIndex() == -1: + comboBox.setToolTip(self.data_reader.data["butler"]["powers"][j][i][1]) + else: + comboBox.setToolTip('') + + def changedButlerRoot(self): + i = self.liMaidRoot.currentIndex() + self.liMaidRoot.setToolTip(self.data_reader.data["butler"]["roots"][i][1]) + + def changedButlerQuality(self): + comboBox = self.sender() + i = comboBox.currentIndex() + if not i == -1: + comboBox.setToolTip(self.data_reader.data["butler"]["qualities"][i][1]) + else: + comboBox.setToolTip('') + + def changedButlerWeapon(self): + comboBox = self.sender() + i = comboBox.currentIndex() + if not i == -1: + comboBox.setToolTip(self.data_reader.data["butler"]["weapons"][i][1]) + else: + comboBox.setToolTip('') + + def setButlerRootComboBox(self): + for elem in self.data_reader.data["butler"]["roots"]: + self.liMaidRoot.insertItem(100, elem[0]) + + self.liMaidRoot.setCurrentIndex(-1) + + def setButlerTypeComboBox(self, comboBox): + for elem in self.data_reader.data["butler"]["types"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def setButlerQualityComboBox(self, comboBox): + for elem in self.data_reader.data["butler"]["qualities"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def setButlerWeaponComboBox(self, comboBox): + for elem in self.data_reader.data["butler"]["weapons"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def generateButler(self): + self.generateAge(True) + self.generateSuitColor(True) + self.generateHairColor(True) + self.generateEyeColor(True) + self.generateAttribute(self.bATH) + self.generateAttribute(self.bAFF) + self.generateAttribute(self.bSKI) + self.generateAttribute(self.bCNN) + self.generateLuckAttribute(True) + self.generateWilAttribute(True) + self.generateButlerType(self.bFirstType) + self.generateButlerType(self.bSecondType) + self.generateButlerRoot(True) + self.generateButlerQuality(self.bSpec1) + self.generateButlerQuality(self.bSpec2) + if self.bSpec3.isEnabled(): + self.generateButlerQuality(self.bSpec3) + if self.bSpec4.isEnabled(): + self.generateButlerQuality(self.bSpec4) + if self.bSpec5.isEnabled(): + self.generateButlerQuality(self.bSpec5) + self.generateButlerWeapon(self.bWeap) + self.generateButlerWeapon(self.bWeap2) + + def saveButler(self): + savePath = QtWidgets.QFileDialog.getSaveFileName(None, 'Save your butler as...', '', + 'Text Documents (*.txt);;All files (*.*)') + if not savePath[0] == '': + starSeparator = '-----------------------------------------------------------------------------------------\n' + printList = [] + printList.append(starSeparator) + printList.append('Name: ' + self.liName.text() + '\n') + printList.append('Age: ' + str(self.liAge.value()) + '\n') + printList.append('Suit color: ' + self.liUniColor.text() + '\n') + printList.append('Eye color: ' + self.liEyeColor.text() + '\n') + printList.append('Hair color: ' + self.liHairColor.text() + '\n') + printList.append(starSeparator) + printList.append('Stats:\n') + printList.append('Athletics: ' + str(self.stats[0]) + '\n') + printList.append('Affection: ' + str(self.stats[1]) + '\n') + printList.append('Skill: ' + str(self.stats[2]) + '\n') + printList.append('Cunning: ' + str(self.stats[3]) + '\n') + printList.append('Luck: ' + str(self.stats[4]) + '\n') + printList.append('Will: ' + str(self.stats[5]) + '\n') + printList.append(self.favor.text() + '\n') + printList.append(self.spirit.text() + '\n') + printList.append(starSeparator) + printList.append('Butler types:\n') + printList.append(self.liFirstType.currentText() + ': ' + self.liFirstType.toolTip() + '\n') + printList.append(self.liSecondType.currentText() + ': ' + self.liSecondType.toolTip() + '\n') + printList.append('\n') + printList.append('Butler powers:\n') + printList.append(self.liMP.currentText() + ': ' + self.liMP.toolTip() + '\n') + if self.liMP2.isEnabled(): + printList.append(self.liMP2.currentText() + ': ' + self.liMP2.toolTip() + '\n') + printList.append('\n') + printList.append('Butler root: ' + self.liMaidRoot.currentText() + '\n') + printList.append(self.liMaidRoot.toolTip() + '\n') + printList.append('\n') + printList.append(starSeparator) + printList.append('Special quailities:\n') + printList.append(self.liSpec1.currentText() + ': ' + self.liSpec1.toolTip() + '\n') + printList.append(self.liSpec2.currentText() + ': ' + self.liSpec2.toolTip() + '\n') + if self.liSpec3.isEnabled(): + printList.append(self.liSpec3.currentText() + ': ' + self.liSpec3.toolTip() + '\n') + if self.liSpec4.isEnabled(): + printList.append(self.liSpec4.currentText() + ': ' + self.liSpec4.toolTip() + '\n') + if self.liSpec5.isEnabled(): + printList.append(self.liSpec5.currentText() + ': ' + self.liSpec5.toolTip() + '\n') + printList.append(starSeparator) + printList.append('Weapon: ' + self.liWeapon.currentText() + '\n') + printList.append(self.liWeapon.toolTip() + '\n') + printList.append('\n') + printList.append('Weapon 2: ' + self.liWeapon2.currentText() + '\n') + printList.append(self.liWeapon2.toolTip() + '\n') + f = open(savePath[0], 'w+') + for line in printList: + f.write(line) + + f.close() + return diff --git a/src/modules/data_reader.py b/src/modules/data_reader.py new file mode 100644 index 0000000..8bd9ac9 --- /dev/null +++ b/src/modules/data_reader.py @@ -0,0 +1,59 @@ +import os.path +import json +import sys +from random import randrange, randint + + +class MaidDataReader: + PATH = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "data.json") + + def __init__(self): + self.data = None + with open(MaidDataReader.PATH, "r") as f: + content = f.read() + self.data = json.loads(content) + + if self.data is None: + sys.exit("Could not read JSON data.") + + rare_color_count = len(self.data["common"]["colors"]["rare"]) + self.color_random_max = rare_color_count + 2 * len(self.data["common"]["colors"]["double_chance"]) + self.rare_color_start_index = self.color_random_max - rare_color_count + + def get_random_color(self): + index = randrange(self.color_random_max) + if index >= self.rare_color_start_index: + return self.data["common"]["colors"]["rare"][index - self.rare_color_start_index] + + return self.data["common"]["colors"]["double_chance"][int(index / 2)] + + def get_butler_random_suit_color(self): + return self.__get_butler_random_color(self.data["butler"]["colors"]["suit"]) + + def get_butler_random_hair_color(self): + return self.__get_butler_random_color(self.data["butler"]["colors"]["hair"]) + + @staticmethod + def generate_master_age(type_index): + if type_index == 0: + return randint(1, 6) + randint(1, 6) + elif type_index == 1: + return randint(1, 6) + randint(1, 6) + 5 + elif type_index == 2: + return randint(1, 6) + randint(1, 6) + 8 + elif type_index == 3: + return randint(1, 6) + randint(1, 6) + 12 + elif type_index == 4: + return int(str(randint(1, 6)) + str(randint(1, 6))) + elif type_index == 5: + return int(str(randint(1, 6)) + str(randint(1, 6))) + 10 + + raise ValueError("Invalid master type index: {}".format(type_index)) + + def __get_butler_random_color(self, color_list): + index = randrange(len(color_list) + 1) + if index >= len(color_list): + return self.get_random_color() + + return color_list[index] + diff --git a/src/modules/helpWidget.py b/src/modules/helpWidget.py new file mode 100644 index 0000000..c2c9794 --- /dev/null +++ b/src/modules/helpWidget.py @@ -0,0 +1,31 @@ +""" +Widget for the help dock. +""" +import os.path + +from PyQt5 import QtWidgets, QtGui, QtCore + +class CHelpWidget(QtWidgets.QWidget): + + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.parent = parent + self.loVLayoutMain = QtWidgets.QVBoxLayout() + self.loHLayoutMain = QtWidgets.QHBoxLayout() + self.loVLayoutMain.setAlignment(QtCore.Qt.AlignTop) + self.helpText = QtWidgets.QLabel("To fully generate a maid press the 'GENERATE MAID' button. In a case of identical stat values " + 'you have to choose which stat to use when rolling for maid power. You can do this with ' + "the 'MP' button. To generate a second maid power (if available) hold down the 'Shift' key " + "then press the 'MP' button of your choosing (from the available options).\n\n" + "To reroll a singe value press the corresponding 'R' button.\n" + 'To roll a Special quality from a specific secondary table (for example: Magic) choose that primary table from the popuplist ' + "then press the corresponding 'R' button while holding down the 'Shift' key.\n\n" + 'Hover your cursor over a choosen trait to see its description.\n\n' + "To save your maid in a txt file press the 'SAVE' button.\n\n\n" + "PS.: There are no easter eggs in this program. Do not try out famous cheat codes.") + self.helpText.setWordWrap(True) + self.loVLayoutMain.addWidget(self.helpText) + hlayout = QtWidgets.QHBoxLayout() + hlayout.setAlignment(QtCore.Qt.AlignCenter) + self.picture = QtWidgets.QLabel() + maid_picture_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "ram.png") + self.picture.setPixmap(QtGui.QPixmap(maid_picture_path).scaled(360, 360)) + self.picture.setGeometry(0, 0, 360, 360) + hlayout.addWidget(self.picture) + self.loVLayoutMain.addLayout(hlayout) + self.loHLayoutMain.addLayout(self.loVLayoutMain) + self.setLayout(self.loHLayoutMain) + + def easterEgg(self): + self.parent.parent.statusbarMessage.setText('ALL YOUR MAID ARE BELONG TO US') diff --git a/src/modules/maidWidget.py b/src/modules/maidWidget.py new file mode 100644 index 0000000..44865b0 --- /dev/null +++ b/src/modules/maidWidget.py @@ -0,0 +1,845 @@ +""" +Widget for the random maid dock. +""" +from random import randint +from math import floor +from PyQt5 import QtWidgets, QtCore + +class CMaidWidget(QtWidgets.QWidget): + + def __init__(self, data_reader, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.data_reader = data_reader + self.parent = parent + + self.stats = [0, 0, 0, 0, 0, 0] + self.rebuildingMaidPowers = False + + self.loVLayoutMain = QtWidgets.QVBoxLayout() + self.loHLayoutMain = QtWidgets.QHBoxLayout() + + self.gbBasic = QtWidgets.QGroupBox('Basics', self) + self.loGbBasic = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Name: ') + hLayout.addWidget(textLabel) + self.liName = QtWidgets.QLineEdit() + self.liName.setFixedWidth(200) + hLayout.addWidget(self.liName) + hLayout.addStretch(1) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Age: ') + hLayout.addWidget(textLabel) + self.liAge = QtWidgets.QSpinBox() + self.liAge.setFixedWidth(50) + self.liAge.setMaximum(9999) + hLayout.addWidget(self.liAge) + hLayout.addStretch(1) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Uniform color: ') + hLayout.addWidget(textLabel) + self.liUniColor = QtWidgets.QLineEdit() + self.liUniColor.setFixedWidth(150) + hLayout.addWidget(self.liUniColor) + self.bUniColor = QtWidgets.QPushButton('R') + self.bUniColor.parent = self.liUniColor + self.bUniColor.setFixedWidth(50) + hLayout.addWidget(self.bUniColor) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Eye color: ') + hLayout.addWidget(textLabel) + self.liEyeColor = QtWidgets.QLineEdit() + self.liEyeColor.setFixedWidth(150) + hLayout.addWidget(self.liEyeColor) + self.bEyeColor = QtWidgets.QPushButton('R') + self.bEyeColor.setFixedWidth(50) + self.bEyeColor.parent = self.liEyeColor + hLayout.addWidget(self.bEyeColor) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Hair color: ') + hLayout.addWidget(textLabel) + self.liHairColor = QtWidgets.QLineEdit() + self.liHairColor.setFixedWidth(150) + hLayout.addWidget(self.liHairColor) + self.bHairColor = QtWidgets.QPushButton('R') + self.bHairColor.setFixedWidth(50) + self.bHairColor.parent = self.liHairColor + hLayout.addWidget(self.bHairColor) + self.loGbBasic.addLayout(hLayout) + self.gbBasic.setLayout(self.loGbBasic) + self.loH1 = QtWidgets.QHBoxLayout() + self.loH1.addWidget(self.gbBasic) + self.gbMaidType = QtWidgets.QGroupBox('Maid Type', self) + self.loGbMaidType = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('First: ') + hLayout.addWidget(textLabel) + self.liFirstType = QtWidgets.QComboBox() + self.setMaidTypeComboBox(self.liFirstType) + self.liFirstType.setFixedWidth(100) + hLayout.addWidget(self.liFirstType) + self.bFirstType = QtWidgets.QPushButton('R') + self.bFirstType.setFixedWidth(50) + self.bFirstType.parent = self.liFirstType + hLayout.addWidget(self.bFirstType) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.descFirst = QtWidgets.QLabel('') + self.descFirst.setWordWrap(True) + self.liFirstType.desc = self.descFirst + self.liFirstType.changeList = [0, 0, 0, 0, 0, 0] + hLayout.addWidget(self.descFirst) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Second: ') + hLayout.addWidget(textLabel) + self.liSecondType = QtWidgets.QComboBox() + self.setMaidTypeComboBox(self.liSecondType) + self.liSecondType.setFixedWidth(100) + hLayout.addWidget(self.liSecondType) + self.bSecondType = QtWidgets.QPushButton('R') + self.bSecondType.setFixedWidth(50) + self.bSecondType.parent = self.liSecondType + hLayout.addWidget(self.bSecondType) + self.loGbMaidType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.descSecond = QtWidgets.QLabel('') + self.descSecond.setWordWrap(True) + self.liSecondType.desc = self.descSecond + self.liSecondType.changeList = [0, 0, 0, 0, 0, 0] + hLayout.addWidget(self.descSecond) + self.loGbMaidType.addLayout(hLayout) + self.gbMaidType.setLayout(self.loGbMaidType) + self.gbMaidType.setFixedWidth(220) + self.loH1.addWidget(self.gbMaidType) + self.gbAttri = QtWidgets.QGroupBox('Attributes', self) + self.loGbAttri = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('ATH:') + textLabel.setToolTip('Athletics: Physical ability, combat ability.') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liATH = QtWidgets.QSpinBox() + self.liATH.setFixedWidth(35) + hLayout.addWidget(self.liATH, 1, QtCore.Qt.AlignRight) + self.textATH = QtWidgets.QLabel('(0)') + self.liATH.sumVal = self.textATH + hLayout.addWidget(self.textATH, 1, QtCore.Qt.AlignRight) + self.bATH = QtWidgets.QPushButton('R') + self.bATH.setFixedWidth(50) + self.bATH.parent = self.liATH + hLayout.addWidget(self.bATH, 1, QtCore.Qt.AlignRight) + self.bMpATH = QtWidgets.QPushButton('MP') + self.bMpATH.setFixedWidth(50) + self.bMpATH.statType = 0 + self.liATH.mpButton = self.bMpATH + hLayout.addWidget(self.bMpATH, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('AFF:') + textLabel.setToolTip('Affection: How good are you at forming bonds with your master and the other maids?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liAFF = QtWidgets.QSpinBox() + self.liAFF.setFixedWidth(35) + hLayout.addWidget(self.liAFF, 1, QtCore.Qt.AlignRight) + self.textAFF = QtWidgets.QLabel('(0)') + self.liAFF.sumVal = self.textAFF + hLayout.addWidget(self.textAFF, 1, QtCore.Qt.AlignRight) + self.bAFF = QtWidgets.QPushButton('R') + self.bAFF.setFixedWidth(50) + self.bAFF.parent = self.liAFF + hLayout.addWidget(self.bAFF, 1, QtCore.Qt.AlignRight) + self.bMpAFF = QtWidgets.QPushButton('MP') + self.bMpAFF.setFixedWidth(50) + self.bMpAFF.statType = 1 + self.liAFF.mpButton = self.bMpAFF + hLayout.addWidget(self.bMpAFF, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('SKI:') + textLabel.setToolTip('Skill: How good are you at your maid duties?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liSKI = QtWidgets.QSpinBox() + self.liSKI.setFixedWidth(35) + hLayout.addWidget(self.liSKI, 1, QtCore.Qt.AlignRight) + self.textSKI = QtWidgets.QLabel('(0)') + self.liSKI.sumVal = self.textSKI + hLayout.addWidget(self.textSKI, 1, QtCore.Qt.AlignRight) + self.bSKI = QtWidgets.QPushButton('R') + self.bSKI.setFixedWidth(50) + self.bSKI.parent = self.liSKI + hLayout.addWidget(self.bSKI, 1, QtCore.Qt.AlignRight) + self.bMpSKI = QtWidgets.QPushButton('MP') + self.bMpSKI.setFixedWidth(50) + self.bMpSKI.statType = 2 + self.liSKI.mpButton = self.bMpSKI + hLayout.addWidget(self.bMpSKI, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('CNN:') + textLabel.setToolTip('Cunning: How capable are you at tricking enemies and other maids, and deceiving the master?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liCNN = QtWidgets.QSpinBox() + self.liCNN.setFixedWidth(35) + hLayout.addWidget(self.liCNN, 1, QtCore.Qt.AlignRight) + self.textCNN = QtWidgets.QLabel('(0)') + self.liCNN.sumVal = self.textCNN + hLayout.addWidget(self.textCNN, 1, QtCore.Qt.AlignRight) + self.bCNN = QtWidgets.QPushButton('R') + self.bCNN.setFixedWidth(50) + self.bCNN.parent = self.liCNN + hLayout.addWidget(self.bCNN, 1, QtCore.Qt.AlignRight) + self.bMpCNN = QtWidgets.QPushButton('MP') + self.bMpCNN.setFixedWidth(50) + self.bMpCNN.statType = 3 + self.liCNN.mpButton = self.bMpCNN + hLayout.addWidget(self.bMpCNN, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('LCK:') + textLabel.setToolTip('Luck: Just how lucky are you?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liLCK = QtWidgets.QSpinBox() + self.liLCK.setFixedWidth(35) + hLayout.addWidget(self.liLCK, 1, QtCore.Qt.AlignRight) + self.textLCK = QtWidgets.QLabel('(0)') + self.liLCK.sumVal = self.textLCK + hLayout.addWidget(self.textLCK, 1, QtCore.Qt.AlignRight) + self.bLCK = QtWidgets.QPushButton('R') + self.bLCK.setFixedWidth(50) + self.bLCK.parent = self.liLCK + hLayout.addWidget(self.bLCK, 1, QtCore.Qt.AlignRight) + self.bMpLCK = QtWidgets.QPushButton('MP') + self.bMpLCK.setFixedWidth(50) + self.bMpLCK.statType = 4 + self.liLCK.mpButton = self.bMpLCK + hLayout.addWidget(self.bMpLCK, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('WIL:') + textLabel.setToolTip('Will: How positive and constructive is your thinking?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liWIL = QtWidgets.QSpinBox() + self.liWIL.setFixedWidth(35) + hLayout.addWidget(self.liWIL, 1, QtCore.Qt.AlignRight) + self.textWIL = QtWidgets.QLabel('(0)') + self.liWIL.sumVal = self.textWIL + hLayout.addWidget(self.textWIL, 1, QtCore.Qt.AlignRight) + self.bWIL = QtWidgets.QPushButton('R') + self.bWIL.setFixedWidth(50) + self.bWIL.parent = self.liWIL + hLayout.addWidget(self.bWIL, 1, QtCore.Qt.AlignRight) + self.bMpWIL = QtWidgets.QPushButton('MP') + self.bMpWIL.setFixedWidth(50) + self.bMpWIL.statType = 5 + self.liWIL.mpButton = self.bMpWIL + hLayout.addWidget(self.bMpWIL, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + self.gbAttri.setLayout(self.loGbAttri) + self.loH2 = QtWidgets.QHBoxLayout() + self.loH2.addWidget(self.gbAttri) + self.gbEtc = QtWidgets.QGroupBox('Etcetera', self) + self.loGbEtc = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Maid root: ') + hLayout.addWidget(textLabel) + self.liMaidRoot = QtWidgets.QComboBox() + self.setMaidRootComboBox() + self.liMaidRoot.setFixedWidth(130) + hLayout.addWidget(self.liMaidRoot) + self.bMaidRoot = QtWidgets.QPushButton('R') + self.bMaidRoot.parent = self.liMaidRoot + self.bMaidRoot.setFixedWidth(50) + hLayout.addWidget(self.bMaidRoot) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Stress explosion: ') + hLayout.addWidget(textLabel) + self.liStress = QtWidgets.QComboBox() + self.setStressExplosionComboBox() + self.liStress.setFixedWidth(130) + hLayout.addWidget(self.liStress) + self.bStress = QtWidgets.QPushButton('R') + self.bStress.parent = self.liStress + self.bStress.setFixedWidth(50) + hLayout.addWidget(self.bStress) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Maid power: ') + hLayout.addWidget(textLabel) + self.liMP = QtWidgets.QComboBox() + self.liMP.setFixedWidth(150) + hLayout.addWidget(self.liMP) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Maid power 2: ') + hLayout.addWidget(textLabel) + self.liMP2 = QtWidgets.QComboBox() + self.liMP2.setFixedWidth(150) + hLayout.addWidget(self.liMP2) + self.loGbEtc.addLayout(hLayout) + + self.favor = QtWidgets.QLabel('Favor: 0') + self.spirit = QtWidgets.QLabel('Spirit: 0') + self.loGbEtc.addWidget(self.favor) + self.loGbEtc.addWidget(self.spirit) + + self.gbEtc.setLayout(self.loGbEtc) + self.loH2.addWidget(self.gbEtc) + self.gbSpec = QtWidgets.QGroupBox('Special Qualities', self) + self.loGbSpec = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec1 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec1) + self.liSpec1.setFixedWidth(150) + hLayout.addWidget(self.liSpec1, 10, QtCore.Qt.AlignRight) + self.bSpec1 = QtWidgets.QPushButton('R') + self.bSpec1.setFixedWidth(50) + self.bSpec1.parent = self.liSpec1 + hLayout.addWidget(self.bSpec1, 0, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec2 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec2) + self.liSpec2.setFixedWidth(150) + hLayout.addWidget(self.liSpec2, 10, QtCore.Qt.AlignRight) + self.bSpec2 = QtWidgets.QPushButton('R') + self.bSpec2.setFixedWidth(50) + self.bSpec2.parent = self.liSpec2 + hLayout.addWidget(self.bSpec2, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec3 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec3, 1, QtCore.Qt.AlignRight) + self.liSpec3 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec3) + self.liSpec3.setFixedWidth(150) + hLayout.addWidget(self.liSpec3, 1, QtCore.Qt.AlignRight) + self.bSpec3 = QtWidgets.QPushButton('R') + self.bSpec3.setFixedWidth(50) + self.bSpec3.parent = self.liSpec3 + self.cbSpec3.button = self.bSpec3 + self.cbSpec3.box = self.liSpec3 + hLayout.addWidget(self.bSpec3, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec4 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec4, 1, QtCore.Qt.AlignRight) + self.liSpec4 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec4) + self.liSpec4.setFixedWidth(150) + hLayout.addWidget(self.liSpec4, 1, QtCore.Qt.AlignRight) + self.bSpec4 = QtWidgets.QPushButton('R') + self.bSpec4.setFixedWidth(50) + self.bSpec4.parent = self.liSpec4 + self.cbSpec4.button = self.bSpec4 + self.cbSpec4.box = self.liSpec4 + hLayout.addWidget(self.bSpec4, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec5 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec5, 1, QtCore.Qt.AlignRight) + self.liSpec5 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec5) + self.liSpec5.setFixedWidth(150) + hLayout.addWidget(self.liSpec5, 1, QtCore.Qt.AlignRight) + self.bSpec5 = QtWidgets.QPushButton('R') + self.bSpec5.setFixedWidth(50) + self.bSpec5.parent = self.liSpec5 + self.cbSpec5.button = self.bSpec5 + self.cbSpec5.box = self.liSpec5 + hLayout.addWidget(self.bSpec5, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + self.gbSpec.setLayout(self.loGbSpec) + self.gbSpec.setFixedWidth(250) + + self.loH3 = QtWidgets.QHBoxLayout() + self.loH3.addWidget(self.gbSpec) + self.gbWeap = QtWidgets.QGroupBox('Weapon', self) + self.loGbWeap = QtWidgets.QVBoxLayout() + self.cbEnableWeapon = QtWidgets.QCheckBox('Enable weapon') + self.cbEnableWeapon.setChecked(True) + self.loGbWeap.addWidget(self.cbEnableWeapon) + self.liWeapon = QtWidgets.QComboBox() + self.setWeaponComboBox() + self.loGbWeap.addWidget(self.liWeapon) + self.bWeap = QtWidgets.QPushButton('R') + self.loGbWeap.addWidget(self.bWeap) + self.cbEnableWeapon.button = self.bWeap + self.cbEnableWeapon.box = self.liWeapon + self.gbWeap.setLayout(self.loGbWeap) + self.loH3.addWidget(self.gbWeap) + + self.gbSave = QtWidgets.QGroupBox('Generate and save', self) + self.loGbSave = QtWidgets.QVBoxLayout() + self.bRollAll = QtWidgets.QPushButton('GENERATE\nMAID', self) + self.loGbSave.addWidget(self.bRollAll) + self.bSave = QtWidgets.QPushButton('SAVE', self) + self.loGbSave.addWidget(self.bSave) + self.gbSave.setLayout(self.loGbSave) + self.gbSave.setFixedWidth(120) + self.loH3.addWidget(self.gbSave) + + self.loVLayoutMain.addLayout(self.loH1) + self.loVLayoutMain.addLayout(self.loH2) + self.loVLayoutMain.addLayout(self.loH3) + self.loHLayoutMain.addLayout(self.loVLayoutMain) + self.setLayout(self.loHLayoutMain) + + self.setEnabilities() + self.setMaidPowerComboBox(self.liMP, [0, 1, 2, 3, 4, 5]) + self.setMaidPowerComboBox(self.liMP2, [0, 1, 2, 3, 4, 5]) + self.bATH.clicked.connect(self.generateAttribute) + self.bAFF.clicked.connect(self.generateAttribute) + self.bSKI.clicked.connect(self.generateAttribute) + self.bCNN.clicked.connect(self.generateAttribute) + self.bLCK.clicked.connect(self.generateAttribute) + self.bWIL.clicked.connect(self.generateAttribute) + self.bFirstType.clicked.connect(self.generateMaidType) + self.bSecondType.clicked.connect(self.generateMaidType) + self.bUniColor.clicked.connect(self.generateMaidColor) + self.bEyeColor.clicked.connect(self.generateMaidColor) + self.bHairColor.clicked.connect(self.generateMaidColor) + self.bSpec1.clicked.connect(self.generateSpecialQuality) + self.bSpec2.clicked.connect(self.generateSpecialQuality) + self.bSpec3.clicked.connect(self.generateSpecialQuality) + self.bSpec4.clicked.connect(self.generateSpecialQuality) + self.bSpec5.clicked.connect(self.generateSpecialQuality) + self.bWeap.clicked.connect(self.generateWeapon) + self.bMaidRoot.clicked.connect(self.generateMaidRoot) + self.bStress.clicked.connect(self.generateStressExplosion) + self.bMpATH.clicked.connect(self.generateMaidPower) + self.bMpAFF.clicked.connect(self.generateMaidPower) + self.bMpSKI.clicked.connect(self.generateMaidPower) + self.bMpCNN.clicked.connect(self.generateMaidPower) + self.bMpLCK.clicked.connect(self.generateMaidPower) + self.bMpWIL.clicked.connect(self.generateMaidPower) + self.bRollAll.clicked.connect(self.generateFullMaid) + self.bSave.clicked.connect(self.saveMaid) + self.cbEnableWeapon.clicked.connect(self.setEnabilities) + self.cbSpec3.clicked.connect(self.setEnabilities) + self.cbSpec4.clicked.connect(self.setEnabilities) + self.cbSpec5.clicked.connect(self.setEnabilities) + self.liFirstType.currentIndexChanged.connect(self.changedMaidType) + self.liSecondType.currentIndexChanged.connect(self.changedMaidType) + self.liSpec1.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec2.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec3.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec4.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec5.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liWeapon.currentIndexChanged.connect(self.changedWeapon) + self.liMaidRoot.currentIndexChanged.connect(self.changedMaidRoot) + self.liStress.currentIndexChanged.connect(self.changedStressExplosion) + self.liATH.valueChanged.connect(self.calculateStats) + self.liAFF.valueChanged.connect(self.calculateStats) + self.liSKI.valueChanged.connect(self.calculateStats) + self.liCNN.valueChanged.connect(self.calculateStats) + self.liLCK.valueChanged.connect(self.calculateStats) + self.liWIL.valueChanged.connect(self.calculateStats) + self.liMP.activated.connect(self.changedMaidPower) + self.liMP2.activated.connect(self.changedMaidPower) + + def setEnabilities(self): + for checkb in [self.cbEnableWeapon, self.cbSpec3, self.cbSpec4, self.cbSpec5]: + if not checkb.isChecked(): + checkb.button.setEnabled(False) + checkb.box.setEnabled(False) + checkb.box.setCurrentIndex(-1) + else: + checkb.button.setEnabled(True) + checkb.box.setEnabled(True) + + def generateAttribute(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled attribute...', 1500) + x = randint(1, 6) + y = randint(1, 6) + retVal = int(floor((x + y) / 3)) + caller.parent.setValue(retVal) + + def generateMaidType(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled maid type...', 1500) + i = randint(0, 5) + caller.parent.setCurrentIndex(i) + + def generateMaidColor(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled color...', 1500) + caller.parent.setText(self.data_reader.get_random_color()) + + def generateWeapon(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled weapon...', 1500) + i = randint(0, 35) + self.liWeapon.setCurrentIndex(i) + + def generateMaidRoot(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled maid root...', 1500) + i = randint(0, 17) + self.liMaidRoot.setCurrentIndex(i) + + def generateStressExplosion(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled stress explosion...', 1500) + i = randint(0, 17) + self.liStress.setCurrentIndex(i) + + def generateMaidPower(self, caller=False, generateSecond=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled maid power...', 1500) + if not QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier and not generateSecond: + upperLimit = self.liMP.count() + desiredStat = caller.statType + while True: + success = False + while True: + i = randint(0, upperLimit - 1) + text = self.liMP.itemText(i) + if text != self.liMP2.currentText(): + break + + for elem in self.data_reader.data["maid"]["powers"][desiredStat]: + if elem[0] == text: + success = True + self.liMP.setCurrentIndex(i) + break + + if success: + break + + self.changedMaidPower(self.liMP) + elif self.liMP2.isEnabled(): + upperLimit = self.liMP2.count() + desiredStat = caller.statType + while True: + success = False + while True: + i = randint(0, upperLimit - 1) + text = self.liMP2.itemText(i) + if text != self.liMP.currentText(): + break + + for elem in self.data_reader.data["maid"]["powers"][desiredStat]: + if elem[0] == text: + success = True + self.liMP2.setCurrentIndex(i) + break + + if success: + break + + self.changedMaidPower(self.liMP2) + + def generateSpecialQuality(self, caller=False): + onlySecondary = False + allowed2Go = True + if caller == False: + if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: + onlySecondary = True + caller = self.sender() + if onlySecondary: + if caller.parent.currentIndex() < 18: + allowed2Go = False + if allowed2Go: + self.parent.parent.statusBar().showMessage('Rolled special quality...', 1500) + if allowed2Go: + i = -1 + if not onlySecondary: + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + if i > 17 or i == -1: + i = randint(37, 42) + caller.parent.setCurrentIndex(i) + + def calculateStats(self): + stat0 = self.liATH.value() + self.liFirstType.changeList[0] + self.liSecondType.changeList[0] + stat1 = self.liAFF.value() + self.liFirstType.changeList[1] + self.liSecondType.changeList[1] + stat2 = self.liSKI.value() + self.liFirstType.changeList[2] + self.liSecondType.changeList[2] + stat3 = self.liCNN.value() + self.liFirstType.changeList[3] + self.liSecondType.changeList[3] + stat4 = self.liLCK.value() + self.liFirstType.changeList[4] + self.liSecondType.changeList[4] + stat5 = self.liWIL.value() + self.liFirstType.changeList[5] + self.liSecondType.changeList[5] + self.stats = [stat0, stat1, stat2, stat3, stat4, stat5] + for i in range(len(self.stats)): + if self.stats[i] < 0: + self.stats[i] = 0 + + self.liATH.sumVal.setText('(' + str(self.stats[0]) + ')') + self.liAFF.sumVal.setText('(' + str(self.stats[1]) + ')') + self.liSKI.sumVal.setText('(' + str(self.stats[2]) + ')') + self.liCNN.sumVal.setText('(' + str(self.stats[3]) + ')') + self.liLCK.sumVal.setText('(' + str(self.stats[4]) + ')') + self.liWIL.sumVal.setText('(' + str(self.stats[5]) + ')') + self.favor.setText('Favor: ' + str(self.stats[1] * 2)) + self.spirit.setText('Spirit: ' + str(self.stats[5] * 10)) + highestValue = -1 + for i in range(len(self.stats)): + if highestValue < self.stats[i]: + highestValue = self.stats[i] + + highestValueList = [] + buttonList = [ + self.bMpATH, self.bMpAFF, self.bMpSKI, self.bMpCNN, self.bMpLCK, self.bMpWIL] + for i in range(len(self.stats)): + if self.stats[i] == highestValue: + buttonList[i].setEnabled(True) + highestValueList.append(i) + else: + buttonList[i].setEnabled(False) + + if self.stats[0] + self.stats[1] + self.stats[2] + self.stats[3] + self.stats[4] + self.stats[5] < 10: + self.liMP2.setEnabled(True) + else: + self.liMP2.setCurrentIndex(-1) + self.liMP2.setEnabled(False) + self.setMaidPowerComboBox(self.liMP, highestValueList) + self.setMaidPowerComboBox(self.liMP2, highestValueList) + + def changedMaidType(self): + comboBox = self.sender() + elem = self.data_reader.data["maid"]["types"][comboBox.currentIndex()] + comboBox.setToolTip(elem[1]) + comboBox.changeList = elem[2] + comboBox.desc.setText(elem[3]) + self.calculateStats() + + def changedMaidPower(self, comboBox=0): + if not self.rebuildingMaidPowers: + if type(comboBox) is int: + comboBox = self.sender() + text = comboBox.currentText() + found = False + for stat in self.data_reader.data["maid"]["powers"]: + for elem in stat: + if elem[0] == text: + comboBox.setToolTip(elem[1]) + found = True + + if comboBox.currentIndex() == -1 or found == False: + comboBox.setToolTip('') + + def changedSpecialQuailty(self): + comboBox = self.sender() + if comboBox.currentIndex() < 36: + if not comboBox.currentIndex() == -1: + if comboBox.count() > 36: + for i in range(7): + comboBox.removeItem(36) + + elem = self.data_reader.data["maid"]["qualities"][comboBox.currentIndex()] + comboBox.setToolTip(elem[1]) + if elem[2] is not None: + comboBox.setStyleSheet('color: olive') + comboBox.insertSeparator(36) + for item in reversed(elem[2]): + comboBox.insertItem(37, item[0]) + + comboBox.previousIndex = comboBox.currentIndex() + else: + comboBox.setStyleSheet('color: black') + else: + comboBox.setStyleSheet('color: black') + comboBox.setToolTip('') + else: + comboBox.setStyleSheet('color: black') + item = self.data_reader.data["maid"]["qualities"][comboBox.previousIndex][2][(comboBox.currentIndex() - 37)] + comboBox.setToolTip(item[1]) + + def changedWeapon(self): + if not self.liWeapon.currentIndex() == -1: + desc = self.data_reader.data["maid"]["weapons"][self.liWeapon.currentIndex()][1] + self.liWeapon.setToolTip(desc) + else: + self.liWeapon.setToolTip('') + + def changedMaidRoot(self): + self.liMaidRoot.setToolTip(self.data_reader.data["maid"]["roots"][self.liMaidRoot.currentIndex()][1]) + + def changedStressExplosion(self): + self.liStress.setToolTip(self.data_reader.data["common"]["stress_explosions"][self.liStress.currentIndex()][1]) + + def setMaidPowerComboBox(self, comboBox, highestStats): + self.rebuildingMaidPowers = True + text = comboBox.itemText(comboBox.currentIndex()) + for i in range(comboBox.count()): + comboBox.removeItem(0) + + for statNumber in highestStats: + for elem in self.data_reader.data["maid"]["powers"][statNumber]: + comboBox.insertItem(100, elem[0]) + + comboBox.insertSeparator(100) + + comboBox.removeItem(comboBox.count() - 1) + listOfNames = [ comboBox.itemText(i) for i in range(comboBox.count()) ] + comboBox.setCurrentIndex(-1) + for i in range(len(listOfNames)): + if listOfNames[i] == text: + comboBox.setCurrentIndex(i) + + self.rebuildingMaidPowers = False + self.changedMaidPower(comboBox) + + def setMaidTypeComboBox(self, comboBox): + for elem in self.data_reader.data["maid"]["types"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + comboBox.previousIndex = -1 + + def setSpecialQualityComboBox(self, comboBox): + for elem in self.data_reader.data["maid"]["qualities"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def setWeaponComboBox(self): + for elem in self.data_reader.data["maid"]["weapons"]: + self.liWeapon.insertItem(100, elem[0]) + + self.liWeapon.setCurrentIndex(-1) + + def setMaidRootComboBox(self): + for elem in self.data_reader.data["maid"]["roots"]: + self.liMaidRoot.insertItem(100, elem[0]) + + self.liMaidRoot.setCurrentIndex(-1) + + def setStressExplosionComboBox(self): + for elem in self.data_reader.data["common"]["stress_explosions"]: + self.liStress.insertItem(100, elem[0]) + + self.liStress.setCurrentIndex(-1) + + def generateFullMaid(self): + self.generateMaidColor(self.bUniColor) + self.generateMaidColor(self.bHairColor) + self.generateMaidColor(self.bEyeColor) + self.generateAttribute(self.bATH) + self.generateAttribute(self.bAFF) + self.generateAttribute(self.bSKI) + self.generateAttribute(self.bCNN) + self.generateAttribute(self.bLCK) + self.generateAttribute(self.bWIL) + self.generateMaidType(self.bFirstType) + self.generateMaidType(self.bSecondType) + self.liMP.setCurrentIndex(-1) + self.liMP2.setCurrentIndex(-1) + onlyButton = None + for button in [self.bMpATH, self.bMpAFF, self.bMpSKI, self.bMpCNN, self.bMpLCK, self.bMpWIL]: + if button.isEnabled(): + if onlyButton == None: + onlyButton = button + elif onlyButton == 'MORE': + continue + else: + onlyButton = 'MORE' + + if onlyButton != None and onlyButton != 'MORE': + self.generateMaidPower(onlyButton) + if self.liMP2.isEnabled(): + self.generateMaidPower(onlyButton, True) + self.generateMaidRoot(True) + self.generateStressExplosion(True) + self.generateSpecialQuality(self.bSpec1) + self.generateSpecialQuality(self.bSpec2) + if self.liSpec3.isEnabled(): + self.generateSpecialQuality(self.bSpec3) + if self.liSpec4.isEnabled(): + self.generateSpecialQuality(self.bSpec4) + if self.liSpec5.isEnabled(): + self.generateSpecialQuality(self.bSpec5) + if self.liWeapon.isEnabled(): + self.generateWeapon(True) + return + + def saveMaid(self): + savePath = QtWidgets.QFileDialog.getSaveFileName(None, 'Save your maid as...', '', 'Text Documents (*.txt);;All files (*.*)') + if not savePath[0] == '': + starSeparator = '-----------------------------------------------------------------------------------------\n' + printList = [] + printList.append(starSeparator) + printList.append('Name: ' + self.liName.text() + '\n') + printList.append('Age: ' + str(self.liAge.value()) + '\n') + printList.append('Uniform color: ' + self.liUniColor.text() + '\n') + printList.append('Eye color: ' + self.liEyeColor.text() + '\n') + printList.append('Hair color: ' + self.liHairColor.text() + '\n') + printList.append(starSeparator) + printList.append('Stats:\n') + printList.append('Athletics: ' + str(self.stats[0]) + '\n') + printList.append('Affection: ' + str(self.stats[1]) + '\n') + printList.append('Skill: ' + str(self.stats[2]) + '\n') + printList.append('Cunning: ' + str(self.stats[3]) + '\n') + printList.append('Luck: ' + str(self.stats[4]) + '\n') + printList.append('Will: ' + str(self.stats[5]) + '\n') + printList.append(self.favor.text() + '\n') + printList.append(self.spirit.text() + '\n') + printList.append(starSeparator) + printList.append('Maid types:\n') + printList.append(self.liFirstType.currentText() + ': ' + self.liFirstType.toolTip() + '\n') + printList.append(self.liSecondType.currentText() + ': ' + self.liSecondType.toolTip() + '\n') + printList.append('\n') + printList.append('Maid powers:\n') + printList.append(self.liMP.currentText() + ': ' + self.liMP.toolTip() + '\n') + if self.liMP2.isEnabled(): + printList.append(self.liMP2.currentText() + ': ' + self.liMP2.toolTip() + '\n') + printList.append('\n') + printList.append('Maid root: ' + self.liMaidRoot.currentText() + '\n') + printList.append(self.liMaidRoot.toolTip() + '\n') + printList.append('\n') + printList.append('Stress explosion: ' + self.liStress.currentText() + '\n') + printList.append(self.liStress.toolTip() + '\n') + printList.append(starSeparator) + printList.append('Special quailities:\n') + printList.append(self.liSpec1.currentText() + ': ' + self.liSpec1.toolTip() + '\n') + printList.append(self.liSpec2.currentText() + ': ' + self.liSpec2.toolTip() + '\n') + if self.liSpec3.isEnabled(): + printList.append(self.liSpec3.currentText() + ': ' + self.liSpec3.toolTip() + '\n') + if self.liSpec4.isEnabled(): + printList.append(self.liSpec4.currentText() + ': ' + self.liSpec4.toolTip() + '\n') + if self.liSpec5.isEnabled(): + printList.append(self.liSpec5.currentText() + ': ' + self.liSpec5.toolTip() + '\n') + printList.append(starSeparator) + if self.liWeapon.isEnabled(): + printList.append('Weapon: ' + self.liWeapon.currentText() + '\n') + printList.append(self.liWeapon.toolTip() + '\n') + f = open(savePath[0], 'w+') + for line in printList: + f.write(line) + + f.close() + return diff --git a/src/modules/masterWidget.py b/src/modules/masterWidget.py new file mode 100644 index 0000000..bde645a --- /dev/null +++ b/src/modules/masterWidget.py @@ -0,0 +1,677 @@ +""" +Widget for the random master dock. +""" +from random import randint +from math import floor +from PyQt5 import QtWidgets, QtCore + +class CMasterWidget(QtWidgets.QWidget): + + def __init__(self, data_reader, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.data_reader = data_reader + self.parent = parent + + self.stats = [0, 0, 0, 0, 0, 0] + + self.loVLayoutMain = QtWidgets.QVBoxLayout() + self.loHLayoutMain = QtWidgets.QHBoxLayout() + + self.gbBasic = QtWidgets.QGroupBox('Basics', self) + self.loGbBasic = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Name: ') + hLayout.addWidget(textLabel) + self.liName = QtWidgets.QLineEdit() + self.liName.setFixedWidth(200) + hLayout.addWidget(self.liName) + hLayout.addStretch(1) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Gender: ') + hLayout.addWidget(textLabel) + self.rbMale = QtWidgets.QRadioButton('Male') + self.rbFemale = QtWidgets.QRadioButton('Female') + hLayout.addWidget(self.rbMale) + hLayout.addWidget(self.rbFemale) + self.rbMale.setChecked(True) + self.bgGender = QtWidgets.QButtonGroup() + self.bgGender.addButton(self.rbMale) + self.bgGender.addButton(self.rbFemale) + self.bGender = QtWidgets.QPushButton('R') + self.bGender.setFixedWidth(50) + hLayout.addWidget(self.bGender) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Eye color: ') + hLayout.addWidget(textLabel) + self.liEyeColor = QtWidgets.QLineEdit() + self.liEyeColor.setFixedWidth(150) + hLayout.addWidget(self.liEyeColor) + self.bEyeColor = QtWidgets.QPushButton('R') + self.bEyeColor.setFixedWidth(50) + self.bEyeColor.parent = self.liEyeColor + hLayout.addWidget(self.bEyeColor) + self.loGbBasic.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Hair color: ') + hLayout.addWidget(textLabel) + self.liHairColor = QtWidgets.QLineEdit() + self.liHairColor.setFixedWidth(150) + hLayout.addWidget(self.liHairColor) + self.bHairColor = QtWidgets.QPushButton('R') + self.bHairColor.setFixedWidth(50) + self.bHairColor.parent = self.liHairColor + hLayout.addWidget(self.bHairColor) + self.loGbBasic.addLayout(hLayout) + self.gbBasic.setLayout(self.loGbBasic) + self.loH1 = QtWidgets.QHBoxLayout() + self.loH1.addWidget(self.gbBasic) + self.gbMasterType = QtWidgets.QGroupBox('Master Type', self) + self.loGbMasterType = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Type: ') + hLayout.addWidget(textLabel) + self.liMasterType = QtWidgets.QComboBox() + self.liMasterType.setFixedWidth(100) + self.setMasterTypeComboBox() + hLayout.addWidget(self.liMasterType) + self.bMT = QtWidgets.QPushButton('R') + self.bMT.setFixedWidth(50) + hLayout.addWidget(self.bMT) + self.loGbMasterType.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Age: ') + hLayout.addWidget(textLabel) + self.spAge = QtWidgets.QSpinBox() + self.spAge.setFixedWidth(50) + self.spAge.setMaximum(9999) + hLayout.addWidget(self.spAge) + self.bAge = QtWidgets.QPushButton('R') + self.bAge.setFixedWidth(50) + hLayout.addWidget(self.bAge) + self.loGbMasterType.addLayout(hLayout) + self.laAge = QtWidgets.QLabel('Age dice: ') + self.loGbMasterType.addWidget(self.laAge) + self.gbMasterType.setLayout(self.loGbMasterType) + self.gbMasterType.setFixedHeight(160) + self.gbMasterType.setFixedWidth(210) + self.loH1.addWidget(self.gbMasterType) + self.gbAttri = QtWidgets.QGroupBox('Attributes', self) + self.loGbAttri = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('ATH:') + textLabel.setToolTip('Athletics: Physical ability, combat ability.') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liATH = QtWidgets.QSpinBox() + self.liATH.setFixedWidth(35) + hLayout.addWidget(self.liATH, 1, QtCore.Qt.AlignRight) + self.bATH = QtWidgets.QPushButton('R') + self.bATH.setFixedWidth(50) + self.bATH.parent = self.liATH + hLayout.addWidget(self.bATH, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('AFF:') + textLabel.setToolTip('Affection: How good are you at forming bonds with the maids?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liAFF = QtWidgets.QSpinBox() + self.liAFF.setFixedWidth(35) + hLayout.addWidget(self.liAFF, 1, QtCore.Qt.AlignRight) + self.bAFF = QtWidgets.QPushButton('R') + self.bAFF.setFixedWidth(50) + self.bAFF.parent = self.liAFF + hLayout.addWidget(self.bAFF, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('SKI:') + textLabel.setToolTip('Skill: How good are you at your duties?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liSKI = QtWidgets.QSpinBox() + self.liSKI.setFixedWidth(35) + hLayout.addWidget(self.liSKI, 1, QtCore.Qt.AlignRight) + self.bSKI = QtWidgets.QPushButton('R') + self.bSKI.setFixedWidth(50) + self.bSKI.parent = self.liSKI + hLayout.addWidget(self.bSKI, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('CNN:') + textLabel.setToolTip('Cunning: How capable are you at tricking enemies and the maids?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liCNN = QtWidgets.QSpinBox() + self.liCNN.setFixedWidth(35) + hLayout.addWidget(self.liCNN, 1, QtCore.Qt.AlignRight) + self.bCNN = QtWidgets.QPushButton('R') + self.bCNN.setFixedWidth(50) + self.bCNN.parent = self.liCNN + hLayout.addWidget(self.bCNN, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('LCK:') + textLabel.setToolTip('Luck: Just how lucky are you?') + hLayout.addWidget(textLabel, 1, QtCore.Qt.AlignRight) + self.liLCK = QtWidgets.QSpinBox() + self.liLCK.setFixedWidth(35) + hLayout.addWidget(self.liLCK, 1, QtCore.Qt.AlignRight) + self.bLCK = QtWidgets.QPushButton('R') + self.bLCK.setFixedWidth(50) + self.bLCK.parent = self.liLCK + hLayout.addWidget(self.bLCK, 1, QtCore.Qt.AlignRight) + self.loGbAttri.addLayout(hLayout) + textLabel = QtWidgets.QLabel(' WIL: 2') + textLabel.setToolTip('Luck: Just how lucky are you?') + self.loGbAttri.addWidget(textLabel) + textLabel = QtWidgets.QLabel(' Spirit: 20') + self.loGbAttri.addWidget(textLabel) + self.gbAttri.setLayout(self.loGbAttri) + self.gbAttri.setFixedWidth(150) + self.gbAttri.setFixedHeight(200) + self.loH2 = QtWidgets.QHBoxLayout() + self.loH2.addWidget(self.gbAttri) + self.gbEtc = QtWidgets.QGroupBox('Etcetera', self) + self.loGbEtc = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Master power source: ') + hLayout.addWidget(textLabel) + self.liMP = QtWidgets.QComboBox() + self.liMP.setFixedWidth(130) + self.setMasterPowerComboBox(self.liMP) + hLayout.addWidget(self.liMP) + self.bMP = QtWidgets.QPushButton('R') + self.bMP.parent = self.liMP + self.bMP.setFixedWidth(50) + hLayout.addWidget(self.bMP) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Master power source 2: ') + hLayout.addWidget(textLabel) + self.liMP2 = QtWidgets.QComboBox() + self.liMP2.setFixedWidth(130) + self.setMasterPowerComboBox(self.liMP2) + hLayout.addWidget(self.liMP2) + self.bMP2 = QtWidgets.QPushButton('R') + self.bMP2.parent = self.liMP2 + self.bMP2.setFixedWidth(50) + hLayout.addWidget(self.bMP2) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Favorite maid type: ') + hLayout.addWidget(textLabel) + self.liFavorite = QtWidgets.QComboBox() + self.liFavorite.setFixedWidth(130) + self.setFavoriteMaidTypeComboBox() + hLayout.addWidget(self.liFavorite) + self.bFavorite = QtWidgets.QPushButton('R') + self.bFavorite.parent = self.liFavorite + self.bFavorite.setFixedWidth(50) + hLayout.addWidget(self.bFavorite) + self.loGbEtc.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + textLabel = QtWidgets.QLabel('Stress explosion: ') + hLayout.addWidget(textLabel) + self.liStress = QtWidgets.QComboBox() + self.setStressExplosionComboBox() + self.liStress.setFixedWidth(130) + hLayout.addWidget(self.liStress) + self.bStress = QtWidgets.QPushButton('R') + self.bStress.parent = self.liStress + self.bStress.setFixedWidth(50) + hLayout.addWidget(self.bStress) + self.loGbEtc.addLayout(hLayout) + self.gbEtc.setFixedHeight(200) + self.gbEtc.setLayout(self.loGbEtc) + self.loH2.addWidget(self.gbEtc) + self.gbSpec = QtWidgets.QGroupBox('Special Qualities', self) + self.loGbSpec = QtWidgets.QVBoxLayout() + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec1 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec1) + self.liSpec1.setFixedWidth(150) + hLayout.addWidget(self.liSpec1, 10, QtCore.Qt.AlignRight) + self.bSpec1 = QtWidgets.QPushButton('R') + self.bSpec1.setFixedWidth(50) + self.bSpec1.parent = self.liSpec1 + hLayout.addWidget(self.bSpec1, 0, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.liSpec2 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec2) + self.liSpec2.setFixedWidth(150) + hLayout.addWidget(self.liSpec2, 10, QtCore.Qt.AlignRight) + self.bSpec2 = QtWidgets.QPushButton('R') + self.bSpec2.setFixedWidth(50) + self.bSpec2.parent = self.liSpec2 + hLayout.addWidget(self.bSpec2, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec3 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec3, 1, QtCore.Qt.AlignRight) + self.liSpec3 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec3) + self.liSpec3.setFixedWidth(150) + hLayout.addWidget(self.liSpec3, 1, QtCore.Qt.AlignRight) + self.bSpec3 = QtWidgets.QPushButton('R') + self.bSpec3.setFixedWidth(50) + self.bSpec3.parent = self.liSpec3 + self.cbSpec3.button = self.bSpec3 + self.cbSpec3.box = self.liSpec3 + hLayout.addWidget(self.bSpec3, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec4 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec4, 1, QtCore.Qt.AlignRight) + self.liSpec4 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec4) + self.liSpec4.setFixedWidth(150) + hLayout.addWidget(self.liSpec4, 1, QtCore.Qt.AlignRight) + self.bSpec4 = QtWidgets.QPushButton('R') + self.bSpec4.setFixedWidth(50) + self.bSpec4.parent = self.liSpec4 + self.cbSpec4.button = self.bSpec4 + self.cbSpec4.box = self.liSpec4 + hLayout.addWidget(self.bSpec4, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + hLayout = QtWidgets.QHBoxLayout() + self.cbSpec5 = QtWidgets.QCheckBox() + hLayout.addWidget(self.cbSpec5, 1, QtCore.Qt.AlignRight) + self.liSpec5 = QtWidgets.QComboBox() + self.setSpecialQualityComboBox(self.liSpec5) + self.liSpec5.setFixedWidth(150) + hLayout.addWidget(self.liSpec5, 1, QtCore.Qt.AlignRight) + self.bSpec5 = QtWidgets.QPushButton('R') + self.bSpec5.setFixedWidth(50) + self.bSpec5.parent = self.liSpec5 + self.cbSpec5.button = self.bSpec5 + self.cbSpec5.box = self.liSpec5 + hLayout.addWidget(self.bSpec5, 1, QtCore.Qt.AlignRight) + self.loGbSpec.addLayout(hLayout) + + self.gbSpec.setLayout(self.loGbSpec) + self.loH3 = QtWidgets.QHBoxLayout() + self.loH3.addWidget(self.gbSpec) + + self.gbTrauma = QtWidgets.QGroupBox('Trauma', self) + self.loGbTrauma = QtWidgets.QVBoxLayout() + self.cbEnableTrauma = QtWidgets.QCheckBox('Enable trauma') + self.loGbTrauma.addWidget(self.cbEnableTrauma) + self.liTrauma = QtWidgets.QComboBox() + self.setTraumaComboBox() + self.loGbTrauma.addWidget(self.liTrauma) + self.bTrauma = QtWidgets.QPushButton('R') + self.loGbTrauma.addWidget(self.bTrauma) + self.cbEnableTrauma.button = self.bTrauma + self.cbEnableTrauma.box = self.liTrauma + self.gbTrauma.setLayout(self.loGbTrauma) + self.gbTrauma.setFixedWidth(150) + self.loH3.addWidget(self.gbTrauma) + + self.gbSave = QtWidgets.QGroupBox('Generate and save', self) + self.loGbSave = QtWidgets.QVBoxLayout() + self.bRollAll = QtWidgets.QPushButton('GENERATE\nMASTER', self) + self.loGbSave.addWidget(self.bRollAll) + self.bSave = QtWidgets.QPushButton('SAVE', self) + self.loGbSave.addWidget(self.bSave) + self.gbSave.setLayout(self.loGbSave) + self.gbSave.setFixedWidth(120) + self.loH3.addWidget(self.gbSave) + + self.loVLayoutMain.addLayout(self.loH1) + self.loVLayoutMain.addLayout(self.loH2) + self.loVLayoutMain.addLayout(self.loH3) + self.loHLayoutMain.addLayout(self.loVLayoutMain) + self.setLayout(self.loHLayoutMain) + + self.setEnabilities() + self.cbEnableTrauma.clicked.connect(self.setEnabilities) + self.cbSpec3.clicked.connect(self.setEnabilities) + self.cbSpec4.clicked.connect(self.setEnabilities) + self.cbSpec5.clicked.connect(self.setEnabilities) + self.bHairColor.clicked.connect(self.generateMaidColor) + self.bEyeColor.clicked.connect(self.generateMaidColor) + self.bGender.clicked.connect(self.generateGender) + self.bATH.clicked.connect(self.generateAttribute) + self.bAFF.clicked.connect(self.generateAttribute) + self.bSKI.clicked.connect(self.generateAttribute) + self.bCNN.clicked.connect(self.generateAttribute) + self.bLCK.clicked.connect(self.generateAttribute) + self.bMT.clicked.connect(self.generateMasterType) + self.bAge.clicked.connect(self.generateAge) + self.bMP.clicked.connect(self.generateMasterPower) + self.bMP2.clicked.connect(self.generateMasterPower) + self.bStress.clicked.connect(self.generateStressExplosion) + self.bFavorite.clicked.connect(self.generateFavoriteMaidType) + self.bSpec1.clicked.connect(self.generateSpecialQuality) + self.bSpec2.clicked.connect(self.generateSpecialQuality) + self.bSpec3.clicked.connect(self.generateSpecialQuality) + self.bSpec4.clicked.connect(self.generateSpecialQuality) + self.bSpec5.clicked.connect(self.generateSpecialQuality) + self.bTrauma.clicked.connect(self.generateTrauma) + self.liMasterType.currentIndexChanged.connect(self.changedMasterType) + self.liMP.currentIndexChanged.connect(self.changedMasterPower) + self.liMP2.currentIndexChanged.connect(self.changedMasterPower) + self.liStress.currentIndexChanged.connect(self.changedStressExplosion) + self.liFavorite.currentIndexChanged.connect(self.changedFavoriteMaidType) + self.liSpec1.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec2.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec3.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec4.currentIndexChanged.connect(self.changedSpecialQuailty) + self.liSpec5.currentIndexChanged.connect(self.changedSpecialQuailty) + self.bRollAll.clicked.connect(self.generateMaster) + self.bSave.clicked.connect(self.saveMaster) + + def setEnabilities(self): + for checkb in [self.cbEnableTrauma, self.cbSpec3, self.cbSpec4, self.cbSpec5]: + if not checkb.isChecked(): + checkb.button.setEnabled(False) + checkb.box.setEnabled(False) + checkb.box.setCurrentIndex(-1) + else: + checkb.button.setEnabled(True) + checkb.box.setEnabled(True) + + def generateMaidColor(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled color...', 1500) + caller.parent.setText(self.data_reader.get_random_color()) + + def generateGender(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled gender...', 1500) + i = randint(0, 1) + if i == 0: + self.rbMale.setChecked(True) + else: + self.rbFemale.setChecked(True) + + def generateAttribute(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled attribute...', 1500) + x = randint(1, 6) + y = randint(1, 6) + retVal = int(floor((x + y) / 4)) + caller.parent.setValue(retVal) + + def generateMasterType(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled master type...', 1500) + i = randint(0, 5) + self.liMasterType.setCurrentIndex(i) + + def generateAge(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled age...', 1500) + self.spAge.setValue(self.data_reader.generate_master_age(self.liMasterType.currentIndex())) + + def generateMasterPower(self, caller=False): + if caller == False: + caller = self.sender() + self.parent.parent.statusBar().showMessage('Rolled master power...', 1500) + x = randint(1, 6) + y = randint(1, 6) + i = x + y - 2 + caller.parent.setCurrentIndex(i) + + def generateStressExplosion(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled stress explosion...', 1500) + i = randint(0, 17) + self.liStress.setCurrentIndex(i) + + def generateFavoriteMaidType(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled favorite maid type...', 1500) + i = randint(0, 5) + self.liFavorite.setCurrentIndex(i) + + def generateTrauma(self, hideMessage=False): + if not hideMessage: + self.parent.parent.statusBar().showMessage('Rolled trauma...', 1500) + i = randint(0, 35) + self.liTrauma.setCurrentIndex(i) + + def generateSpecialQuality(self, caller=False): + onlySecondary = False + allowed2Go = True + inWhichTable = 0 + if caller == False: + if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: + onlySecondary = True + caller = self.sender() + if onlySecondary: + if caller.parent.currentIndex() < 35: + allowed2Go = False + if allowed2Go: + self.parent.parent.statusBar().showMessage('Rolled special quality...', 1500) + if caller.parent.currentIndex() < 36: + inWhichTable = 1 + elif caller.parent.currentIndex() < 55: + inWhichTable = 2 + else: + inWhichTable = 3 + if allowed2Go: + if inWhichTable == 1: + i = -1 + if not onlySecondary: + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + if i == 35: + i = randint(37, 54) + caller.parent.setCurrentIndex(i) + i = randint(56, 61) + caller.parent.setCurrentIndex(i) + elif caller.parent.currentIndex() == 35: + i = randint(37, 54) + caller.parent.setCurrentIndex(i) + elif inWhichTable == 2: + i = -1 + if not onlySecondary: + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + else: + i = randint(56, 61) + caller.parent.setCurrentIndex(i) + elif inWhichTable == 3: + i = -1 + if not onlySecondary: + i = randint(0, 35) + caller.parent.setCurrentIndex(i) + else: + i = randint(56, 61) + caller.parent.setCurrentIndex(i) + + def changedMasterType(self): + ii = self.liMasterType.currentIndex() + type_of_master = self.data_reader.data["master"]["types"][ii] + self.liMasterType.setToolTip(type_of_master[1]) + self.laAge.setText('Age dice: {}'.format(type_of_master[2])) + self.spAge.setValue(self.data_reader.generate_master_age(ii)) + + def changedMasterPower(self, caller=False): + comboBox = self.sender() + comboBox.setToolTip(self.data_reader.data["master"]["powers"][comboBox.currentIndex()][1]) + + def changedStressExplosion(self): + self.liStress.setToolTip(self.data_reader.data["common"]["stress_explosions"][self.liStress.currentIndex()][1]) + + def changedFavoriteMaidType(self): + elem = self.data_reader.data["maid"]["types"][self.liFavorite.currentIndex()] + self.liFavorite.setToolTip(elem[1]) + + def changedSpecialQuailty(self): + comboBox = self.sender() + if comboBox.currentIndex() < 36: + if not comboBox.currentIndex() == -1: + if comboBox.count() > 36: + for i in range(26): + comboBox.removeItem(36) + + elem = self.data_reader.data["master"]["qualities"][comboBox.currentIndex()] + comboBox.setToolTip(elem[1]) + if comboBox.currentIndex() == 35: + comboBox.setStyleSheet('color: olive') + comboBox.insertSeparator(36) + for elem in reversed(self.data_reader.data["maid"]["qualities"][18:]): + comboBox.insertItem(37, elem[0]) + + else: + comboBox.setStyleSheet('color: black') + else: + comboBox.setStyleSheet('color: black') + comboBox.setToolTip('') + elif comboBox.currentIndex() < 55: + comboBox.setStyleSheet('color: olive') + for i in range(7): + comboBox.removeItem(55) + + comboBox.insertSeparator(55) + elem = self.data_reader.data["maid"]["qualities"][18:][(comboBox.currentIndex() - 37)] + comboBox.setToolTip(elem[1]) + comboBox.previousIndex = comboBox.currentIndex() + for item in reversed(elem[2]): + comboBox.insertItem(56, item[0]) + + else: + comboBox.setStyleSheet('color: black') + item = self.data_reader.data["maid"]["qualities"][18:][(comboBox.previousIndex - 37)][2][(comboBox.currentIndex() - 56)] + comboBox.setToolTip(item[1]) + + def setMasterTypeComboBox(self): + for elem in self.data_reader.data["master"]["types"]: + self.liMasterType.insertItem(100, elem[0]) + + self.liMasterType.setCurrentIndex(-1) + + def setMasterPowerComboBox(self, comboBox): + for elem in self.data_reader.data["master"]["powers"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def setStressExplosionComboBox(self): + for elem in self.data_reader.data["common"]["stress_explosions"]: + self.liStress.insertItem(100, elem[0]) + + self.liStress.setCurrentIndex(-1) + + def setFavoriteMaidTypeComboBox(self): + for elem in self.data_reader.data["maid"]["types"]: + self.liFavorite.insertItem(100, elem[0]) + + self.liFavorite.setCurrentIndex(-1) + + def setSpecialQualityComboBox(self, comboBox): + for elem in self.data_reader.data["master"]["qualities"]: + comboBox.insertItem(100, elem[0]) + + comboBox.setCurrentIndex(-1) + + def setTraumaComboBox(self): + for elem in self.data_reader.data["master"]["traumas"]: + self.liTrauma.insertItem(100, elem) + + self.liTrauma.setCurrentIndex(-1) + + def generateMaster(self): + self.generateGender(True) + self.generateMaidColor(self.bEyeColor) + self.generateMaidColor(self.bHairColor) + self.generateAttribute(self.bATH) + self.generateAttribute(self.bAFF) + self.generateAttribute(self.bSKI) + self.generateAttribute(self.bCNN) + self.generateAttribute(self.bLCK) + self.generateMasterPower(self.bMP) + self.generateMasterPower(self.bMP2) + self.generateFavoriteMaidType(True) + self.generateMasterType(True) + self.generateStressExplosion(True) + self.generateSpecialQuality(self.bSpec1) + self.generateSpecialQuality(self.bSpec2) + if self.bSpec3.isEnabled(): + self.generateSpecialQuality(self.bSpec3) + if self.bSpec4.isEnabled(): + self.generateSpecialQuality(self.bSpec4) + if self.bSpec5.isEnabled(): + self.generateSpecialQuality(self.bSpec5) + if self.bTrauma.isEnabled(): + self.generateTrauma(True) + + def saveMaster(self): + savePath = QtWidgets.QFileDialog.getSaveFileName(None, 'Save your master as...', '', 'Text Documents (*.txt);;All files (*.*)') + if not savePath[0] == '': + starSeparator = '-----------------------------------------------------------------------------------------\n' + printList = [] + printList.append(starSeparator) + printList.append('Name: ' + self.liName.text() + '\n') + printList.append('Age: ' + str(self.spAge.value()) + '\n') + genderText = 'male' + if self.rbFemale.isChecked(): + genderText = 'female' + printList.append('Gender: ' + genderText + '\n') + printList.append('Eye color: ' + self.liEyeColor.text() + '\n') + printList.append('Hair color: ' + self.liHairColor.text() + '\n') + printList.append(starSeparator) + printList.append('Stats:\n') + printList.append('Athletics: ' + str(self.liATH.value()) + '\n') + printList.append('Affection: ' + str(self.liAFF.value()) + '\n') + printList.append('Skill: ' + str(self.liSKI.value()) + '\n') + printList.append('Cunning: ' + str(self.liCNN.value()) + '\n') + printList.append('Luck: ' + str(self.liLCK.value()) + '\n') + printList.append('Will: 2\n') + printList.append('Spirit: 20\n') + printList.append(starSeparator) + printList.append('Master type:' + self.liMasterType.currentText() + '\n') + printList.append(self.liMasterType.toolTip() + '\n') + printList.append('\n') + printList.append('Master powers:\n') + printList.append(self.liMP.currentText() + ': ' + self.liMP.toolTip() + '\n') + printList.append(self.liMP2.currentText() + ': ' + self.liMP2.toolTip() + '\n') + printList.append('\n') + printList.append('Favorite maid type: ' + self.liFavorite.currentText() + '\n') + printList.append(self.liFavorite.toolTip() + '\n') + printList.append('\n') + printList.append('Stress explosion: ' + self.liStress.currentText() + '\n') + printList.append(self.liStress.toolTip() + '\n') + printList.append(starSeparator) + printList.append('Special quailities:\n') + printList.append(self.liSpec1.currentText() + ': ' + self.liSpec1.toolTip() + '\n') + printList.append(self.liSpec2.currentText() + ': ' + self.liSpec2.toolTip() + '\n') + if self.liSpec3.isEnabled(): + printList.append(self.liSpec3.currentText() + ': ' + self.liSpec3.toolTip() + '\n') + if self.liSpec4.isEnabled(): + printList.append(self.liSpec4.currentText() + ': ' + self.liSpec4.toolTip() + '\n') + if self.liSpec5.isEnabled(): + printList.append(self.liSpec5.currentText() + ': ' + self.liSpec5.toolTip() + '\n') + printList.append(starSeparator) + if self.liTrauma.isEnabled(): + printList.append('Trauma: ' + self.liTrauma.currentText() + '\n') + printList.append(self.liTrauma.toolTip() + '\n') + f = open(savePath[0], 'w+') + for line in printList: + f.write(line) + + f.close() + return -- cgit v1.2.3-70-g09d2