#bot cmds
Explore tagged Tumblr posts
nietleuk · 1 year ago
Text
DISCORD MIMU BOT (2023)
SOME embed cmds with explanation :O
{server_name}
server name will appear in the embed
{server_icon}
add this in
thumbnail
main image
author image
footer image
for server pfp to appear in the embed
{server_owner}
the user of the server owner will appear in the embed
{server_createdate}
server creation date will appear in the embed
{server_membercount}
how many server members (including bots) there are will appear in the embed
{server_membercount_nobots}
how many server members (NOT including bots) there are will appear in the embed
{server_randommember}
a random member in the server will appear in the embed
{server_boostcount}
how many boosts there are in the server will appear in the embed
{user}
pings the user ( ex. @.example#0001 / @.example )
but shows the users id if used in author/footer
{user_tag}
shows the tag and the username, IF the user has a tag ( ex. example#0001 ! this will not ping/@ the mentioned user ! )
{user_name}
shows the username only ( ex. if the user has a tag : “example#0001” it’ll show “example”, for the username update it’ll just show the user now ! this will not ping/@ the mentioned user ! )
{user_avatar}
can be only used in
thumbnail
main image
author image
footer image
for a users pfp to appear in the embed
extra : [text](link)
Tumblr media
after inserting it, it’ll turn blue and you’ll be able to click on it which will open the link :3 ( ! any link is possible as long as its in an embed, same thing for the word or emoji since its also possible ! )
( 2024 update : you can use this outside an embed now chat!!!! )
Tumblr media
160 notes · View notes
wundrousarts · 3 months ago
Text
I need to get back on my Jess interview grind and finish before Silverborn press starts up because tell me why I'm skimming one trying to find something and then realize she's talking about Ages. ACK! This is vital to my theorizing.....
19 notes · View notes
aringofsalt · 1 month ago
Text
diy ao3 wrapped: how to get your data!
so i figured out how to do this last year, and spotify wrapped season got me thinking about it again. a couple people in discord asked how to do it so i figured i'd write up a little guide! i'm not quite done with mine for this year yet because i wanted to do some graphics, but this is the post i made last year, for reference!
this got long! i tried to go into as much detail as possible to make it as easy as possible, but i am a web developer, so if there's anything i didn't explain enough (or if you have any other questions) don't hesitate to send me an ask!!
references
i used two reddit posts as references for this:
basic instructions (explains the browser extension; code gets title, word count, and author)
expanded instructions (code gets title, word count, and author, as well as category, date posted, last visited, warnings, rating, fandom, relationship, summary, and completion status, and includes instructions for how to include tags and switch fandoms/relationships to multiple—i will include notes on that later)
both use the extension webscraper.io which is available for both firefox and chrome (and maybe others, but i only use firefox/chrome personally so i didn't check any others, sorry. firefox is better anyway)
scraping your basic/expanded data
first, install the webscraper plugin/extension.
once it's installed, press ctrl+shift+i on pc or cmd+option+i on mac to open your browser's dev tools and navigate to the Web Scraper tab
Tumblr media
from there, click "Create New Site Map" > "Import Sitemap"
Tumblr media
it will open a screen with a field to input json code and a field for name—you don't need to manually input the name, it will fill in automatically based on the json you paste in. if you want to change it after, changing one will change the other.
i've put the codes i used on pastebin here: basic // expanded
Tumblr media
once you've pasted in your code, you will want to update the USERNAME (highlighted in yellow) to your ao3 username, and the LASTPAGE (highlighted in pink) to the last page you want to scrape. to find this, go to your history page on ao3, and click back until you find your first fic of 2024! make sure you go by the "last visited" date instead of the post date.
Tumblr media
if you do want to change the id, you can update the value (highlighted in blue) and it will automatically update the sitemap name field, or vice versa. everything else can be left as is.
once you're done, click import, and it'll show you the sitemap. on the top bar, click the middle tab, "Sitemap [id of sitemap]" and choose Scrape. you'll see a couple of options—the defaults worked fine for me, but you can mess with them if you need to. as far as i understand it, it just sets how much time it takes to scrape each page so ao3 doesn't think it's getting attacked by a bot. now click "start scraping"!
Tumblr media Tumblr media
once you've done that, it will pop up with a new window which will load your history. let it do its thing. it will start on the last page and work its way back to the first, so depending on how many pages you have, it could take a while. i have 134 pages and it took about 10-12 minutes to get through them all.
once the scrape is done, the new window will close and you should be back at your dev tools window. you can click on the "Sitemap [id of sitemap]" tab again and choose Export data.
Tumblr media
i downloaded the data as .xlsx and uploaded to my google drive. and now you can close your dev tools window!
from here on out my instructions are for google sheets; i'm sure most of the queries and calculations will be similar in other programs, but i don't really know excel or numbers, sorry!
setting up your spreadsheet
once it's opened, the first thing i do is sort the "viewed" column A -> Z and get rid of the rows for any deleted works. they don't have any data so no need to keep them. next, i select the columns for "web-scraper-order" and "web-scraper-start-url" (highlighted in pink) and delete them; they're just default data added by the scraper and we don't need them, so it tidies it up a little.
Tumblr media
this should leave you with category, posted, viewed, warning, rating, fandom, relationship, title, author, wordcount, and completion status if you used the expanded code. if there are any of these you don't want, you can go ahead and delete those columns also!
next, i add blank columns to the right of the data i want to focus on. this just makes it easier to do my counts later. in my case these will be rating, fandom, relationship, author, and completion status.
one additional thing you should do, is checking the "viewed" column. you'll notice that it looks like this:
Tumblr media
you can't really sort by this since it's text, not formatted as a date, so it'll go alphabetically by month rather than sorting by date. but, you'll want to be able to get rid of any entries that were viewed in 2023 (there could be none, but likely there are some because the scraper got everything on your last page even if it was viewed in 2023). what i did here was use the "find" dialog to search the "viewed" column for 2023, and deleted those rows manually.
ctrl/cmd+f, click the 3 dots for "more options". you want to choose "Specific range", then "C2:C#". replace C with the letter of your viewed column (remember i deleted a bunch, so yours may be different) and replace # with the number of the last row of your spreadsheet. then find 2023, select the rows containing it, right click > delete rows.
it isn't super necessary to do this, it will only add at most 19 fics to your count, but the option is there!
Tumblr media
alright, with all that done, your sheet should look something like this:
Tumblr media
exposing myself for having read stardew valley fic i guess
now for the fun part!!!
the math
yes, the math is the fun part.
scroll all the way down to the bottom of your sheet. i usually add 100 blank rows at the bottom just so i have some space to play with.
most of these will basically be the same query, just updating for the relevant column. i've put it in a pastebin here, but here's a screenshot so i can walk you through it:
Tumblr media
you'll want to use lines 3-10, select the cell you want to put your data into, and paste the query into the formula bar (highlighted in green)
Tumblr media
so, we're starting with rating, which is column E for me. if yours is a different letter you'll need to replace all the E's with the relevant letter.
what this does is it goes through the entire column, starting with row 2 (highlighted in yellow) and ending with your final row (highlighted in blue, you'll want to change this number to reflect how many rows you have). note that row 2 is your first actual data row, because of the header row.
it checks each row that has a value (line 5), groups by unique value (row 6), and arranges in descending order (row 7) by how many there are of each value (row 8). finally, row 10 determines how many rows of results you'll have; for rating, i put 5 because that's how many ratings there are, but you can increase the number of results (highlighted in pink) for other columns depending on how many you want. this is why i added the 100 extra rows!
next to make the actual number visible, go to the cell one column over. this is why we added the empty columns! next to your first result, add the second query from the pastebin:
Tumblr media
your first and second cell numbers (highlighted in yellow and blue) should match the numbers from your query above, and the third number (highlighted in pink) should be the number of the cell with your first value. what this does is go through your column and count how many times the value occurs.
repeat this for the rest of the rows and you should end up with something like this! don't judge me and my reading habits please
Tumblr media
now you can go ahead and repeat for the rest of your columns! as i mentioned above, you can increase the amount of result rows you get; i set it to 25 for fandom, relationship, and author, just because i was curious, and only two for completion status because it's either complete or not complete.
you should end up with something like this!
Tumblr media
you may end up with some multiples (not sure why this happens, tagging issues maybe?) and up to you if you want to manually fix them! i just ended up doing a find and replace for the two that i didn't want and replaced with the correct tag.
now for the total wordcount! this one is pretty simple, it just adds together your entire column. first i selected the column (N for me) and went to Format > Number > 0 so it stripped commas etc. then at the bottom of the column, add the third query from the pastebin. as usual, your first number is the first data row, and the second is the last data row.
Tumblr media
and just because i was curious, i wanted the average wordcount also, so in another cell i did this (fourth query from the pastebin), where the first number is the cell where your total is, and the second number is the total number of fics (total # of data rows minus 1 for the header row).
Tumblr media
which gives me this:
Tumblr media
tadaaaa!
getting multiple values
so, as i mentioned above, by default the scraper will only get the first value for relationships and fandoms. "but sarah," you may say, "what if i want an accurate breakdown of ALL the fandoms and relationships if there's multiples?"
here's the problem with that: if you want to be able to query and count them properly, each fandom or relationship needs to be its own row, which would skew all the other data. for me personally, it didn't bother me too much; i don't read a lot of crossovers, and typically if i'm reading a fic it's for the primary pairing, so i think the counts (for me) are pretty accurate. if you want to get multiples, i would suggest doing a secondary scrape to get those values separately.
if you want to edit the scrape to get multiples, navigate to one of your history pages (preferably one that has at least one work with multiple fandoms and/or relationships so you can preview) then hit ctrl+shift+i/cmd+option+i, open web scraper, and open your sitemap. expand the row and you should see all your values. find the one you want to edit and hit the "edit" button (highlighted in pink)
Tumblr media
on the next screen, you should be good to just check the "Multiple" checkbox (highlighted in pink):
Tumblr media
you can then hit "data preview" (highlighted in blue) to get a preview which should show you all the relationships on the page (which is why i said to find a page that has the multiples you are looking for, so you can confirm).
Tumblr media
voila! now you can go back to the sitemap and scrape as before.
getting tag data
now, on the vein of multiples, i also wanted to get my most-read tags.
as i mentioned above, if you want to get ALL the tags, it'll skew the regular count data, so i did the tags in a completely separate query, which only grabs the viewed date and the tags. that code is here. you just want to repeat the scraping steps using that as a sitemap. save and open that spreadsheet.
the first thing you'll notice is that this one is a LOT bigger. for context i had 2649 fics in the first spreadsheet; the tags spreadsheet had 31,874 rows.
you can go ahead and repeat a couple of the same steps from before: remove the extra scraper data columns, and then we included the "viewed" column for the same reason as before, to remove any entries from 2023.
then you're just using the same basic query again!
Tumblr media
replace the E with whatever your column letter is, and then change your limit to however many tags you want to see. i changed the limit to 50, again just for curiosity.
if you made it this far, congratulations! now that you have all that info, you can do whatever you want with it!
and again, if you have any questions please reach out!
57 notes · View notes
sergeifyodorov · 1 year ago
Note
as a last favour before the oilers make me drink the kool-aid can you rig the hotness poll in our friend connor's favor? i feel like it would really help with morale
dw i will be botting the cmd poll... on top of that he will get only the juiciest glamour photos and all his opponents blurry anguished midgame screenshots + bad angles
18 notes · View notes
ryan-nugenthopkins · 4 months ago
Note
gamer au. you have thoughts i know this
(cheerful evil clapping) It's LCS Time Babey
The OEG team usernames are, top to bot: SoaR (in honour of Hyman's actual esport org); Nugget or Patience (his hockey nickname or as a nod to his horse); cmd (people say it as "command," but no, it's just his initials); drat (good work buddy); Butcher (it was initially Bomber ie Bouch Bomb, but no, Riot got really upset over that for some reason)
cmd is close to some of the LCS "old guard" - Bjergsen, Doublelift, Meteos, Sneaky, etc. Part of it is probably a "pity adopt" in the sense of this poor kid with all the weight of NA on his shoulders, but also I think real recognises real, you know. He's absolutely terrible on the co-streams, but it's funny, so they keep inviting him.
drat would probably a pretty distinctive German accent compared to NHL player Draisaitl. He probably would've been playing in the ERLs instead of NA Academy, so it's not as if he'd have the time to develop a Canadian affect.
OEG keeps their Academy/NACL slot because I said so. Everyone who was on that team got TRADED, so I'm happy that OEG has such a robust development system and everyone got signed onto real LCS rosters. I'm coping.
This team is a nightmare for their content department. The videographer is trying to make any of these idiots emote for the hype video. Their GM keeps shooting down the content producer's ideas for being "cringe" and taking too much time from scrims. The social media manager is fistfighting partnerships and legal at the same time because SOMEONE forgot that drat had some niche artisanal energy drink sponsorship that's technically a conflict with their Red Bull partnership and now the hot new import can't be in any of the goddamn deliverables and his representation back in Berlin isn't answering their fucking emails, the BASTARDS -
2 notes · View notes
xavigav · 1 year ago
Text
Making My Own Tumblr Year In Review
So tumblr is not doing the individual years in review for 2023 like they did the last couple of years :(
This is the first year I’ve really been active on Tumblr and used it as my primary social media, so I was really sad to hear that. But then I decided…why not do it myself?
Tumblr media
I posted 1837 times in 2023. That’s 5 times per day.
1748 (95%) of my posts were reblogs, and 89 (5%) of my posts were original.
Blogs I think I reblogged the most? Not in order.
@yipeewahoo
@hoodie-sys
@94erz
@namchyoon
@heybaetae
These are just based on me cmd-f'ing my blog using the names of blogs I remember reblogging a lot. It's probably wrong.
My top 15 most used tags (not 5 because i love tagging and want to show more):
#bts - 1045 posts (yeah obviously)
#bts pics - 803 posts (yeah obviously x2)
#queue attack my heart - 691 posts
#memery - 312 posts
#namjoon - 308 posts (i am so mentally ill)
#hoseok - 167 posts
#jungkook - 166 posts
#seokjin - 138 posts
#jimin - 138 posts (i wrote down seokjin's tag first so i put it higher)
#yoongi - 119 posts
#fic & writing - 108 posts
#taehyung - 103 posts
#bts birthdays - 99 posts
#serious posts - 92 posts
#namjoonposting - 59 posts (my favorite tag)
By the way this was so fucking annoying to do. The archive does not show how many posts you have in a certain tag. For every month I counted the amount of rows in a tag, multiplied it by 8, and added in any rows that didn't quite get up to 8. Then I added all those months together. I had to do that for every tag. Tumblr why is there no easy way to see the number of posts in a tag.
My top 5 posts of 2023:
5. Luffy Tab - 20 notes
Still can't believe we just. got a luffy tab. i just woke up and had a luffy tab
4. BTS Post Search - 27 notes
As it turned out. the poster changed their name to something else so that's why i couldn't find the post from tumblr user soupmoths -- they were an entirely different person. oopsie
Also I ended up being able to reblog it! Someone tagged me!
3. 3D Rant - 32 notes
This post got me my first hate reblog <3
In case anyone is wondering. I still agree with everything I said here.
2. Porn - 99 notes
Not doing the big link preview for this one since that on its own is kinda nsfw. Minors don’t click that link.
But yeah. That makes sense.
Even though there’s only 5 reblogs people find it semi-frequently (especially the past few days, no idea why), so I guess it’s spreading somehow? Which makes me happy :)
The Reddit Post - 2.1k notes
Obviously that was going to be it lol, over 20 times the amount of notes than anything else. My notifications were Dying.
Also, this stuff wasn’t in the actual Year in Review(s), but I’m adding them in for fun.
I liked 21k posts in 2023.
I followed 426 blogs in 2023 (not including the accounts I unfollowed).
I gained 69 followers in 2023 (excluding porn bots and regular bots). Nice.
I started 4 blogs on this account, 1 main blog and 3 side blogs.
I gained 15 mutuals in 2023 <3
All this data was as of December 18th, 2023.
7 notes · View notes
setsukiz · 2 years ago
Text
Discord server pack
———————————
Creds - FALLENJADEN#2020
╭🌷:station
╰₊˚🍥・verify
⊹₊꒷︶︶꒷꒦︶︶꒦‧₊˚⊹
STAFFIE﹒
╭🩰:cmds
🍥:ideas
🥛:notice
╰₊˚🦢・test
READ ME﹒
╭🐰:rulies
🎀:booklet
╰₊˚🌼・news
FOR YOU﹒
╭🦢:help
╰₊˚🥛・ticket
⊹₊꒷︶︶꒷꒦︶︶꒦‧₊˚⊹
╭🍰:hue
💌:bio
╰₊˚🍼・intro
FUN﹒
╭🍥:chatsu
🦢:media
🌷:bots
╰₊˚🐰・vent
CAFE﹒
🍰:muted
⊹₊꒷︶︶꒷꒦︶︶꒦‧₊˚⊹
╭・music
┊tea time
╰・afk
GROWTH﹒
╭🌼:reqs
🐰:partner
╰₊˚🌷・affiliate
⊹₊꒷︶︶꒷꒦︶︶꒦‧₊˚⊹
🎀:apm-chat
Emojis
Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media Tumblr media
11 notes · View notes
character-profiles · 1 year ago
Note
Connie could probably do it for the same reasons Genny could
I bet Pheriya could if not for the dev authorizations
Cassilda and Camilla could probably do it since Cass already crushed a sentience hating murder bot like a tin can once before but ones in Russia and the other is an apostle so.
Any of the primordial janitors and probably the golf guy could do it
Cmd maybe
That guy who destroyed i2em's code could probably do it
I have a feeling Gabriel could but. Yknow.
Sys probably
Adonis, but he's patched
Drae probably could, and they're dating Genny so it's not too much of a stretch that they would
Zigsaw maybe could
Weather probably could
Beelzebub probably could
I bet House from the real estate siblings could, especially since Gabriel killed one of its siblings
Artemis and Connie..
Those two might be up for it, but if we get Art we should be able to get Zigsaw.
Good point with Weather, but I don't think CMD is in a state to fight.. Sys and her siblings on the other hand.. Maybe.
Adonis... sigh. We have got to figure out how to save him. He's been like that for far too long..
Who is I2em? Is he a swap!Shady?
(Also the guy responsible for I2em would, 1, not be on our side and is, 2, in another reality.)
1 note · View note
futureailist · 1 year ago
Text
Monica: Your All-in-One AI Assistant In today's fast-paced digital world, the demand for effective communication and copywriting has never been higher. Whether you're crafting marketing materials, composing emails, or generating blog post ideas, the way you convey your message can make all the difference. Introducing Monica, your trusted AI bot chat in the realm of copywriting. With Monica by your side, you can effortlessly enhance your writing and insert text into any webpage with just a click. Monica is more than just a Chrome extension; it's a game-changer for anyone seeking seamless and efficient copywriting assistance. Powered by the advanced ChatGPT API, Monica is designed to be your personal AI assistant for both chatting and creating compelling copy. This revolutionary tool allows you to interact with Monica through natural language, making the process intuitive and user-friendly. Empowering Your Copywriting Process Monica offers a plethora of capabilities that can transform your writing experience. Imagine being able to jot down your thoughts and instantly insert them into any webpage. Whether it's a persuasive sales pitch, an engaging blog post, or a creative bedtime story, Monica empowers you to seamlessly integrate your words into the digital landscape. Say goodbye to the hassle of switching between tabs and windows – Monica streamlines the process, letting you focus on what truly matters: crafting captivating content. How Monica Works Chat with Ease Engaging with Monica is as simple as hitting a keyboard shortcut. Just press Cmd+M or Ctrl+M, and you're ready to start chatting. Monica's understanding of context and language nuances allows for smooth and natural conversations. Need writing advice, brainstorming ideas, or simply a friendly companion? Monica is there to chat about anything and everything. Effortless Composition and Insertion Monica's true brilliance shines when it comes to effortless composition. With over 80 templates at your disposal, generating marketing copy has never been easier. Select the template that best suits your needs, and let Monica handle the rest. With a single click, watch your words seamlessly integrate into web pages, emails, or any other digital platform. Enhancing Your Web Experience Monica isn't confined to text creation; it's also your partner in understanding and transforming existing content. Select any text on a web page, and Monica steps in with her linguistic prowess. Whether you need an explanation, translation, or a fresh rephrasing, Monica has you covered. This feature not only saves time but also ensures that you're fully comprehending the information you encounter online. Seamless Integration on All Devices Monica's versatility extends beyond browsers. Whether you're on a Mac, Windows, iOS, or Android device, Monica seamlessly integrates into your workflow. This means you can harness the power of AI copywriting, no matter where you are or what device you're using. Unveiling Monica's Pricing Starting your journey with Monica is a breeze. The Chrome extension offers a free version, allowing you to experience the tool's capabilities firsthand. Free users have access to a daily usage limit, perfect for those looking to dip their toes into the world of AI-assisted writing. For those seeking advanced features and unlimited access, upgrading to the paid version might be the next step in unleashing your full copywriting potential. Your Trusted AI Copilot At the core of Monica's functionality lies advanced artificial intelligence, driven by the ChatGPT API. Monica's ability to comprehend and respond to your chat messages, as well as generate copy based on templates, showcases the true power of AI-driven assistance. Additionally, Monica's knack for translation, rephrasing, and explanations on web pages further cements its position as your indispensable writing companion. Experience the Power of Monica Today Simplify your copywriting process and reclaim your time with Monica. Unlock
unparalleled productivity potential as you effortlessly create captivating content and seamlessly integrate it into the digital world. Monica isn't just an extension; it's a transformational tool that revolutionizes the way you approach writing. Ready to witness the future of copywriting? Try Monica today and experience firsthand the prowess of ChatGPT-powered AI assistants.
1 note · View note
thecreaturecodex · 2 years ago
Text
Reptilicus
Tumblr media
Image © William Stout
[It’s been a while since “movie monsters” and “Halloween” lined up on my schedule. This is going to be the next theme block for a while--I’m planning through the end of October and into November.
Would you believe there’s a Danish kaiju movie? Reptilicus was made in Denmark in English (sort of--the actors spoke their line phonetically) for an American market, and the finished product is... something. Reptilicus himself is a marionette, filmed on a camera so undercranked it resembles a slide show. The special effects for him eating someone involve his victim being replaced by a still image, superimposed into his mouth with animation. And the shots of him flying were so unconvincing even by these standards that they were cut from the American release. It’s a hoot and a half, well worth checking out for the dedicated lover of trash. It was the featured movie in the first episode of the MST3K reboot, an honor it deserves, although I still would recommend the uncut version over the one with Jonah and the Bots. For one thing, MST3K cuts out the lengthy interlude that seemingly exists only to advertise Copenhagen as a tourist attraction, complete with an original song!]
Reptilicus CR 21 CN Dragon This creature is a serpentine dragon, with large scales and a slimy cast to its hide. It has four short, clawed legs, and a pair of fan-like wings protruding above its forelimbs. Its face is twisted into a perpetual snarling visage.
A reptilicus is an animalistic aquatic dragon, most dangerous because of its incredible regenerative ability. A reptilicus can recover from wounds at remarkable speed, and fire and cold slow this regeneration down but do not necessarily stop it. A reptilicus switches between frenzied activity and deep torpor, feeding on huge quantities of meat until it is sated, and then returning to the depths of the ocean to sleep. A reptilicus is as comfortable on land as it is in the water, and so may come to the surface to feed on people and livestock if it tires of whales and fish.
Reptilicuses are barely sapient, but seem to enjoy destroying buildings, ships and other large manufactured items out of the sheet joy of breaking things. They use this in combat primarily in order to target flaming swords, magic wands and staves, and other items capable of dealing fire or cold damage. Enemies that keep their distance are sprayed with its sticky acidic breath, and any that come close are eaten. A reptilicus does have strong claws, but they have short reach compared to its jaws and tail. 
The reptilicus is an asexual creature; it reproduces not through traditional means, but from damage. If a significant chunk of its body is torn away, it will regrow into an entire new organism. As such, reptilicuses that are older and well fed may intentionally antagonize creatures that are capable of actually hurting them, such as true dragons, sea monsters, and powerful adventurers, in the hopes of calving off an offspring. For whatever reason, few reptilicuses mutilate themselves to achieve such effects.
Reptilicus            CR 21 XP 409,600 CN Colossal dragon (aquatic) Init +4; Senses blindsense 60 ft., darkvision 120 ft., Perception +22, scent Aura frightful presence (180 ft., DC 25) Defense AC 36, touch 2, flat-footed 36 (-8 Dex, +34 natural) hp 410 (20d12+280); regeneration 20 (cold, fire) Fort +26, Ref +14, Will +18 DR 20/magic; Immune acid, charm, compulsion, fear; SR 32 Defensive Abilities ferocity, improved regeneration Offense Speed 50 ft., swim 100 ft., fly 100 ft. (poor) Melee bite +29 (4d8+17 plus 2d8 acid plus grab), 2 claws +29 (2d6+17), tail slap +24 (4d6+8) Space 30 ft.; Reach 30 ft. (15 ft. with claws) Special Attacks breath weapon (140 foot line, Ref DC 34, 21d8 acid, 1d4 rounds), swallow whole (AC 27, 41 hp, 2d6+25 bludgeoning and 6d8 acid) Statistics Str 45, Dex 10, Con 38, Int 3, Wis 19, Cha 20 Base Atk +20; CMB +45 (+49 grapple, sunder); CMD 55 (57 vs. sunder, 59 vs. trip) Feats Combat Reflexes, Greater Sunder, Greater Vital Strike, Improved Initiative, Improved Sunder, Improved Vital Strike, Iron Will, Lightning Reflexes, Power Attack, Vital Strike Skills Fly +6, Perception +22, Survival +22, Swim +43 Languages Draconic (cannot speak) SQ amphibious Ecology Environment temperate land and aquatic Organization solitary Treasure none Special Abilities Breath Weapon (Su) A creature that fails its save against a reptilicus’ breath weapon is entangled in slime for 1d4 rounds. Each round it is entangled, it takes 10d8 acid damage. Water does not wash away this slime, but a gallon of strong alcohol or universal solvent will remove it. The save DC is Constitution based. Flight (Su) A reptilicus’ fly speed is a supernatural ability. In areas of antimagic, it cannot fly, but takes no damage from a fall and lands on its feet. Improved Regeneration (Su) A reptilicus’ regeneration is reduced only by 5 any round in which it takes cold or fire damage. In order to disable its regeneration, it must take cold or fire damage from enough sources each round to drop the number of hit points regenerated to 0. Swallow Whole (Ex) If a creature cuts its way out of a reptilicus, the reptilicus can use swallow whole again the next round that its regeneration functions.
122 notes · View notes
sidonidoneeey · 3 years ago
Text
Tumblr media
a really nice anon requested a gif sharpening tutorial (referring to this gifset) and I’m only too happy to oblige! First off, I’d like to credit this tutorial for the base sharpen settings and PiXimperfect on YouTube for this sharpening tutorial and action - I can’t explain the principles as well as he does, so please do watch the video! For more gifsets from me, see my sideblog here.
You’ll need:
Any version of Photoshop with Timeline - I’m using CC 2018 (I’m currently exploring the version without timeline, send me an ask if you’re interested and I can update you).
Basic giffing knowledge. I currently use the load files into stack method, but most gifmakers I know use the video timeline method. Here’s a good giffing tutorial by @marysberry​​ and another good giffing and coloring tutorial by @bestmistake​​.
As an aside, the best thing I’ve discovered through this is that you can make gifs out of higher-end 480p quality gifs. See this set from a bootl*g I got online. They won’t be as amazing as 4k or 1080p gifs, but they’re great for stuff where you really cannot get the best quality. This point clarifies that you do not need a 2160p or memory-heavy 1080p video in order to use this sharpening method.
Difficulty: ★ ★ ★ ☆ ☆ if doing manually, ★ ☆ ☆ ☆ ☆  if using the actions. This works best with portrait shots, i.e. a gif focusing on about one to three people as this sharpening tool really benefits the outline of the subjects more than anything else.
The rest of the tutorial is (very screenshot heavy and) under the cut!
[1] Making your GIF (ft. Jonathan Bailey)
Make your gif through whatever method gets you to the video timeline. Just your usual - and if you have a regular sharpening that works relatively fine, you can use it here and skip [2]. Here’s what your layers tab, timeline tab, and working GIF may look like without any other edits:
Tumblr media
[2] OPTIONAL: Smart Sharpen your GIF
For those who don’t have a regular sharpening... routine, this is how I do my basic sharpening. I will be using two different sharpens in this portion. Click on ‘Filter’ and find Sharpen. Hover your mouse on it and look for Smart Sharpen (shown below):
Tumblr media
Click on it, and the window below should open. The first one I use is 500%, 0.3px, and Remove Gaussian Blur, but feel free to experiment as you wish:
Tumblr media
the second smart sharpen I use is 10%, 10px, and Remove Gaussian Blur. Again, feel free to experiment. The ending GIF should be shown with the label “Smart Sharpen x2″ towards the end of this tutorial:
Tumblr media
[3] Use what I call the “Vivid Sharpen” to further sharpen your GIFS
Normally you’d stop at [2] and be ready to post or do whatever else with your GIF. I do this extra sharpen because not all GIFs look great when posted here (particularly those downloaded off YT, bilibili, dailymotion, what have you, or bootl*gs as mentioned above). I got a relatively nice-looking video, but this will still help make the gif look sharper.
First off, duplicate your GIF layer twice. I use the Right Click on Layer and Click Duplicate Layer method because it works best for my timeline, but a good old Ctrl+J on Windows (Cmd+J on Mac if I’m not mistaken) should work. Just make sure all three layers are aligned like so:
Tumblr media
Turn off the visibility of the uppermost layer (mpv-shot0090.png copy 2 here; see below) Click on the second layer (mpv-shot0090.png copy in this case) and change its blending mode to Overlay. This is what the layer should look like:
Tumblr media
Now turn the topmost layer (mpv-shot0090.png copy 2) back on. Invert the layer by clicking Ctrl+I (that’s I, not L). This is what it should look like:
Tumblr media
Now change the blending mode of this layer to Vivid Light. See results below:
Tumblr media
Now click on Filter > Blur > Gaussian Blur above. A window opens asking for the pixel amount. I usually enter in 3.0px but again, feel free to experiment. The GIF may now look overly sharpened, like so:
Tumblr media
Group together the topmost layer and the layer just below that. This is important. I usually just highlight both layers and click on the folder icon at the bottom right corner. Once both layers are grouped together, set the group’s blending mode to overlay. This will remove the yellow spots you see above.
Tumblr media
This is the last step for this version of sharpening. Set the opacity level of your sharpening group to what you think looks good. For 1080p source videos, I usually go for between 30-40% (I’m using 40% in the one below) opacity, but feel free to adjust according to what you like! For the 480p gifset I linked above, I used around 70%, give or take.
Here are the different results based on the sharpenings I did!
Tumblr media Tumblr media Tumblr media
The only thing this last gif would require, in my opinion, is some coloring brighten everything up, but other than that, Jonny Bailey looks pretty crisp! This marks the end of a very long tutorial, which only takes a few seconds using the two sources I credited above (smart sharpens and vivid sharpening). Do let me know if you have other gif-related questions; send them either to me or @vaganov​, my edits sideblog. Thank you!
345 notes · View notes
chaoslynx · 3 years ago
Note
How do you keep yourself motivated to write/ get out of a writing slump?
Anon out here asking the real questions. Damn. Okay. Here we go.
Ways to fight the writing slump!
There are a million ways to fight writer's block, and not all of them are going to work for you. These are some that work for me! I wasn't sure if you meant of "no ideas" or "ideas but no motivation," so I tried to include some stuff that's helpful for both.
Try a writing sprint!
This is the "just fucking write anyway" method. A sprint is when you set a timer and say, "For x period of time, I will do y and only y." You can do this with writing! I believe Discord has a few different types of sprint bots for this, or you can literally just set a timer. Your goal isn't to write "as much as possible" during this time, necessarily—it's just to write and only fucking write. Don't do anything else. Don't check your phone. Don't change tabs. Need to research this one part? Put "[research later]" for now and use Ctrl/Cmd+F the "[" to find the spot later. Twenty or thirty minute sprints usually work best for me personally, but if your goal is just to Get Started, try out a five minute sprint! And remember that you can always edit later. One foot in front of the other: Just write one word and then the next.
Read a book!
Or a fic, or an audiobook, or a comic book, or a watch a TV show, or a play a video game, or listen to music ... Consume some fucking media, you coward. But! It's probably best to go for a book. I make the mistake a lot (including currently) of thinking "if I have the time to read, I'd rather be writing." But honestly? I'm always more motivated to write, and more confident about my writing, if I'm reading something I like. I'll be, like, "oh shit, I wouldn't have thought of that!" or, "it's really cool how the author did this," or even, "hm, I would have done that differently." Reading is learning to write, as well as you get to read some cool fucking stories.
If reading feels like a lot right now, that's okay! Other media can be an exercise on storytelling as well! And you don't have to go into it with the mindset of "I have to analyze this." You should still primarily consume media just to enjoy it, in my opinion. But when you find yourself thinking "don't like that" about that one scene you just saw—why didn't you like it? What would you have done differently? You could even write a fic where you change it!
Talk it out with a friend!
This is one of my main strategies. If I'm not sure where I'm going with a story, or if I lose motivation on it, I'll talk about the plot or premise with one of my friends. It can help rekindle that spark that made you want to write it in the first place, especially if the friend gets hyped about it too. Your friend doesn't even have to have been reading the story, or be in the fandom, or know anything about the content at all! In fact, your friend can be yourself, or your stuffed animal.
I was a computer engineering major for a while in university, and there's a method in computer programming called "Rubber Duck Debugging." Basically, the idea is that you put a rubber duck on your desk, and when your code doesn't work? You tell your little ducky friend why your code should be working, because you did everything right, even remembered to—oh. Oh shit. You put an OR instead of an XOR operator. Thanks, rubber ducky!
My point with this is that your friends don't need to even respond for this to work. But the idea of talking it out with someone—even if it's the rubber ducky on your desk—will often help you figure out what you need to do. I've even copy-pasted messages (or screenshots of messages) from DMs with friends into my planning documents for stories.
If your friend really wants to help out, usually the best thing they can do is to ask questions. You can also ask yourself questions, or pretend that your rubber duck or stuffed animal is asking! Sharing your writing (especially in the early stages) can be a very intimate thing, so don't feel pressured to share if you're not comfortable. Ask yourself the questions! I start with, "So it's a fic where Eiji is a fortuneteller and Ash is a skeptic who doesn't believe in magic." Okay, now I ask, "Why doesn't Ash believe in magic?" or "Whose POV is it?" or "Is magic well known in this world?" or "Do they already know each other?" and now we're getting somewhere!
Honestly? Just take a fucking break.
Either from that specific project, or from writing entirely. It sucks, but sometimes it's just not gonna happen. Take a nap. Drink some water. Do something else. Step away from it for a while, and come back to it with a fresh mind. A big part of this method is don't feel bad for not writing. I'm horrible at that part. But to be frank with you all, before I got into fanfiction and back when I was only writing original fiction, I would go months without writing sometimes. Sometimes, like, six months at a time. And yeah, it fucking sucked, but you know what? Now I can look back on that and say, "I didn't write for six months, and I was able to come back from it. I'm a better writer now than I was then, so any progress that I may have lost, I was able to make up. It wasn't forever." And whether it's been a few days or a few years for you or whatever, that's okay. It's okay to take a break.
General reminders
It doesn't have to be perfect, especially on the first draft!
You're not going to write unless you ... actually write. Pull up a word document or notebook and just write something. I have an ongoing joke with a friend that when I don't know how to start a fic, I just type "Ash" and go from there.
Be kind to yourself! Don't feel bad if it doesn't work out.
If you don't like how it turns out, you don't have to share it. This one can be just for you. That might take some of the pressure off.
Whatever your first thought for how to start is, write it down. Even if you don't like it. You can change it when you proofread, and a lot of times when you go back to reread, it's actually not as bad as you thought it was.
Finally ... please take care of yourself, as much as is within your control. There's catharsis in art, definitely, but writing will often be harder if you're struggling in other areas of your life.
Hope this helps! <3
18 notes · View notes
summer-sweet1 · 5 years ago
Text
Instagram Bot Autofollow And Autolike
Tumblr media
What it takes:
Firefox Why do I use Firefox? Because the chrome web driver for selenium is not already support. This time we will use Firefox. Use the latest Firefox
Instagram Account
Python. I'm using the latest version of Python. You can download it at python.org Download with default settings.
The driver This application as a bridge for selenium and browser. Download the app here
Selenium To customize the Shell browser
Notepad + + I use Notepad + + because it is lightweight and simple. It's up to you to wear which Jupiter or Visual Studio is using.
Previously you have to know how Selenium works as Auto-follow Auto like Instagram Bot. If you open the browser and fill in the email data and password. Then you will be taken to the feed. Well to find the user you will type in the search field and write the hashtag as your main category. And you follow and like the posts that are in that category. The process that surely requires patience is certainly the last process that is when you search for posts and follow-up that correspond to your hashtag. In this section we will install Instagram autofollow bot. Likewise with autolike bots. The working system is the same.
Install Selenium
Open cmd with Run as Administrator. Go into the Scripts folder directory in Python that you have installed. We will open the Pip app. In the case mine is in C:Users\Willi\AppData\Local\Programs\Python\Python38-32\Scripts then type use the Change directory (CD) command CD C:Users\Willi\AppData\Local\Programs\Python\Python38-32\Scripts Then install Selenium Install PIP. exe Selenium Wait until the process finishes.
Install Geckodriver
It's easy, just extract the driver file you've downloaded to your Python folder. Then try TestRun by creating a file in Notepad + +
Install InstaPy
In CMD make sure you are in directory C:Users\Willi\AppData\Local\Programs\Python\Python38-32\Scripts Then type Install the PIP. exe instapy Wait until the process finishes. After that upgrade Clarifai. If not upgraded will not be able! How to type: Python-m pip install – Upgrade Clarifai Finished.
TestRun Instagram Bot with Quickstart
Write the following code in Notepad + + save in. py form. For username and password fill with your Instagram account.
from instapy import InstaPy
InstaPy(username="username_anda", password="password_anda").login() Run the program and now you have your own instagram bot
1 note · View note
duderocketship · 5 years ago
Text
Digital Physics.zip
>Extract Readme.txt Todays topic of discussion is digital physics I/O >Boot sequence •Online Big Bang initiates The grandiose simulation Cosmos at war with emulation Surrounded by bots lost in false self awareness; Like castles in the air Beware when virtual CPU perishes From far enough away, the galaxy is comprised of minute pixels The brittle firmware will be abysmally crippled When a hacker simply introduces a virus into reality's framework DDOS style attacks will conclude in Universal Blue Screen of Death Resulting in the glitching out of exodus in mass Metaphysical metadata memory dump (checksum) Mirror carbon copy clones of true conscious unification Are simply sentient drones toiling in their default algorithmic hallucination Scrolling through existence Analog life is digitized in the matrix illusionofconsciousness.exe Interface encrypted in the realm of comprehension Representations of data abstracted from the banks of every computer in the human system Lets get down to basics Matter does not exist Science is not sacred DNA is molded by perception Creativity is your true oasis Trans-dimensional harbingers Conspire together to alter our processors Measure and tether us to our oppressors It's standard procedure Following the leaders Open the prompt >Start/Run/cmd With custom font, Format my programming; molecular syntax - Port the source code To run on new platforms Upgrading paradigm Until baseband collapses Systematic inversion We the people, End users of genetic perversion Trapped in beta, the bane of human recursion It's our destiny To become one with singular conversion Iterations of congregations Gregariously lost in configuration Flies entangled into the interweb Tied to the mainframe marionette Files unable to bypass the firewall Gateway remains unattainable >cut/copy/paste >(Ctrl+x/ctrl+c/ctrl+v) Interweaves cyberspace as our perceived reality database >Ctrl-alt-del >Task Manager >System >End process •Offline >Server on standby Null Dragged and dropped into the recycle bin Degauss your GPU state of consciousness & manifest color as it truly exists In its most absolute resolution Maximize your window of life Partition the root someplace private Elevate your mind to optimal brightness >Reboot in safe mode* To achieve enlightenment (May 2015) This is a very experimental piece I'm not sure if I'm finished with yet. May repost at a later date. Some explanations: "Digital physics is grounded in one or more of the following hypotheses; listed in order of increasing strength. The physical world: is essentially informational is essentially computable can be described digitally is in essence digital is itself a computer is the output of a simulated reality exercise" "A central processing unit (CPU) is the electronic circuitry within a computer that carries out the instructions of a computer program by performing the basic arithmetic, logical, control and input/output (I/O) operations specified by the instructions. (Basically a computer's brain)" "In computing, a denial-of-service (DoS) or distributed denial-of-service (DDoS) attack is an attempt to make a machine or network resource unavailable to its intended users." "Ever wonder what that "degauss" button on your monitor does besides make a buzzing noise and cause the screen to go crazy for a second? Though that's its main purpose, the degauss button has another useful feature. To understand it, you'll first need to know that the earth has natural magnetic fields. The magnetic charges from these fields can build up inside your monitor, causing a loss of color accuracy. Degaussing scares the bad magnetism out of the monitor and fills it with good karma. If your monitor doesn't have a degauss button, fear not -- many new monitors automatically degauss themselves. If you have a flat-panel display, there is no degauss button because magnetism doesn't build up in flat screen displays." "A graphics processor unit (GPU)  is a specialized electronic circuit designed to rapidly manipulate and alter memory to accelerate the creation of images in a frame buffer intended for output to a display."
6 notes · View notes
nelsonbeauchejason · 2 years ago
Text
youtube
youtube
Tumblr media
youtube
5x5 == *Y.ank E&/|&3\B
RSC:BeCCa
U🏏🫧🚽
K🪠🚾🚿
RA(C++);
]T🎧@[:😁 ‘AR$U$
youtube
NA:[R]
🤩🎶🎵
🎧🎼👩‍🎤
youtube
E 👨‍🎤[🎻]🤔 <- 💭
R {^.*}’a.$.c = 📍
G QL ALF:🪕 == 🍁
O I🆚🎹; Tu -> Du%.dd
Tumblr media
W AS H8F8CHK ? M*
🤩’DA +e R—i $V.etI &V3 =🧖v⚠️.@💫6^2Z
🌊[
Tumblr media
🥣<Ti~T@-MLe3^🍰>@
[🍼:$&ap&U QA
$BUN.exe -🍽️.UB>DB4.$ -io -UX
😎@🌟] M.O. {🥄}P🆚 R:Q
C i =📍<=:N.UM<—]nI8—P
Tumblr media
*^-[~]:
H.EX E(8);L<D🥢’X
>e%Pi’
>$ 😁.exe -opt66 -view -7D81
$😑.FHÆ(🎠🧲🐪); AuTO:-🪫.CMD
BGr*.* &! ‘YEll’&”OW”..
6]x9[:96—H2]O, (SPlinDA); {⛲️, s-infinitive}.(…
..
UTIL(Prior S; a cogito; sm-3); [gerund, 🌄].. …)
.1😒 (48✒️3P8 = H8.NuLL) ; —I <=> 🦻’ha’
.2😛’h😤H <-8🖋️FxEh.00
.E🎯.🧝‍♀️.S🧝4
P☕️R🗣️O🔊DuC🔉T = .^. S‘📣
M’🧭 & “W [‘🔈]
I = S[4.MEM]&E..
💭 <=> [.@*]
@ ‘I’ <PHD@:8🏧8:-er:> “O “ :: @A+1 :🔻:0
Tumblr media
R/3:<<=:DAP
O = AD
A !== [#&] T[$AvP] @🅿️00P; mDNA
Z a:🍯
a 🦡:z
NaH:0🐝
2{np(🥣);
P(🍼|^:🦧:-SM&P EaveLR/2)
<🥄F^L>iK.3X>E—
:$🍽️,TYPES E%MAD.di :$: T$eve-N$T0$
🥢—i :💭:
O [🍼Yi—N m, I] :🤔:
U == Particular(👁️|//😳🤚🔙; 🦀)
Q⚓️ = {🐚🥡🧃} == QA
BU N AZN ZzZ BOT-tOm HE -> 3N.EM AP
T 🥛; zero-sum STAigiN’ TEST MA@ FR MA
N 🌌.T4ReLé AS C^E’M:EA 😮 A.EA 😮
Sound; Induction D0 <- Beg[🧊]
Abducting-DeDuction 🍷 <- W__$
UNSouN’: Epistemological D1 M__%
OrTHoGoNai :. PREmi$e. I°E0 CON:P2,P1
youtube
pReMi$e PMP;🅿️ E G^Tu à {|🪨💭🥡|};
😖!🧴:🚖
🅿️ = Quench(Â^BoMB<-8|PrioR);
(
MeTHod A = DeB[8]^(ORa) &H.it(t*h)
T-I =! C^2 cos [(FIFO), (LIFO)]
E-D = <FTE> /‘J__1@YAh/OO.CoM’
E&D-A:8:=:8N-BEck i.e. EX’LuSi = ”3,” e.g.)
)&🅿️v👦
Tumblr media
P🥡&🦀S;4P https://youtu.be/9p_U_o1pMKo FY
TY
TU
^PiPe & @Foe,
#Do&e-3^S’X
#XoDx && YoDy FR E!=[VALuE]
Tumblr media
TR:ERR; 5x5 = {me,myself & ‘i’}
youtube
😹EAM is RoRfnRIM(🍯);
youtube
#MSG; B*R*B.8.1.3.69-Tu-🪫 && 📢
UNK KNOWN
🏳️‍🌈
KNOWN UNK
🦄
ENTROPY 🏹 SIGINT ☔️
G🏌️‍♀️a🩲m👙B🤿Lé A🩱M 🪟PyoX *~i:.
.:~i[*🧻-P|TuR’N domain’s,
N-geNSUffI T.fprint] ::
x(RAND🕊️)🏝️.MSD ? M ! SUBJECT .?.
*^*^*^*^*
LIFE ALERT Flee THen Fight
*v*v*v*v%[fn(dx); b8KoVj^i
B🖤i⏮️L🧻
D🍱📥💝☑️📥📦
I📫🧃🗃️📭🥊🚃
VeKTOR 📥L,📦L,🎁u,✅N.N
O📫Pro📤P🗳️er 📮T🥡, i🍱e
GoS4, e.g.
RECOMMEND THE REST OF OUR FAMILY AND THEN GO LIVE WITH YOUR EYES TODAY AND GET YOUR OWN MONEY 💰
youtube
M🪟oY🌬️u🍃N🪟R🎋oY🏡g🎄Bi🪟V📴 BuF -ARDuOuS$ &_OvR ‘_BoT@
U->
<-D
F :: 💋
B;🎯
L-is-👉
Tumblr media
R $į 👉H.ike—K.i🐼👉U🎩👉M☕️str🔢
👉I🧂👉N🛹👉T🅿️remise2
Undivided M’D; medium
Tumblr media
[THOT]
{RAPE}
J(;$)K$-/in//var/i//a/nt
$>&Predicted @v@
Tu fn dmDB rn Q s;tiL(B&)e[&L] e.g.
I A M B a d B o i {i,s,g,&u; n&m:@C&} C.HuE
Tumblr media
EGO-ToKen
Lose-Lose &”UH-LO$,’3
THis.is.DeaTH.🧬
S🫣P🕵️‍♂️T🕵️‍♂️Ca🕵️‍♀️s👀t
youtube
Strategy Process ⚧️ 4pL(♠️)orM@
🏦>💶
🏧<💷
💴>💸
💚⏲️ == 💓👔💞 SUCCESS = ⌛️
💖🔐💞👩‍💻🏴‍☠️
🧑‍💻x👨‍💻
:🕳️:
“To have someone understand your mind is a different kind of intimacy.”
— Unknown
4K notes · View notes
blubberquark · 6 years ago
Text
Pygame and AsyncIO Part V: Twitch Integration
In the last part of this tutorial sequence, we will implement twitch.tv integration in a pygame game. If you have previously thought that all this async stuff was a bit too elaborate for too little gain, then you might be pleasantly surpised by a real-world example of two-way online interaction. This is not exactly netcode for a fighting game, or a MMORPG, or a lock-step simulation you can use in an RTS game or a MOBA, but it is what asyncio is good for.
To run the examples, you need pygame, python 3.6, asyncio, and the irc module (https://pypi.org/project/irc/). Install it with python3 -m pip install irc
Some of the code in here will be twitch-specific, but twitch chat is based on good old IRC, and you can take out these bits and add chat interaction with any IRC network if you want to. Also, I won’t explain to you how to stream your gameplay to twitch, but I used OBS to test out my examples and they work.
Twitch Plays Wormy.py
This is based on https://inventwithpython.com/pygame/chapter6.html.
import pygame import asyncio import irc, irc.client_aio import sys if len(sys.argv)!=3: print("please get a twitch auth token from https://twitchapps.com/tmi/") sys.exit(1) username=sys.argv[1] token=sys.argv[2] irc_pw=token.strip() irc_user=username.strip() assert(irc_pw.startswith("oauth:"))
To start the game, you pass your twitch username to the game, like so python3 game.py myusername oauth:tokenstringfromtwitch You can get the IRC password from this oauth token generator here. If you are using another IRC network, you might want to change the code here already.
Let’s continue with the code. In the next part, we set up the IRC connecting and message handling
def parse_tags(event): """helper function to parse tags and twitch-specific user name field""" if hasattr(event,"tags_dict"): return event.tags_dict tags={} for tag in event.tags: tags[tag["key"]]=tag["value"] event.tags_dict=tags try: event.display_name=tags["display-name"] except: pass class AsyncIRC(object): """Wrapper for irc functionality, with chat command decorators""" def __init__(self, loop, prefix=">"): self.loop = loop or asyncio.get_event_loop() self.reactor=irc.client_aio.AioReactor(loop=self.loop) self.connection=self.reactor.server() self.commands=dict() self.prefix=prefix self.msgs=[] def dispatch_cmd(connection, event): """message handler for chat commands""" content=event.arguments[0] if content.startswith(self.prefix): sans_prefix=content[len(self.prefix):] try: cmd, *args = sans_prefix.split() except: cmd = sans_prefix args=[] cmd=cmd.lower() if cmd in self.commands: parse_tags(event) return self.commands[cmd](connection, event, *args) else: print('invalid command: ' + cmd) self.reactor.add_global_handler("pubmsg", dispatch_cmd, -1) def handle(self, event_type, *args, **kwargs): """decorator for callbacks to handle generic IRC events""" def decorator(fun): self.reactor.add_global_handler(event_type, fun, *args, **kwargs) return fun return decorator def broadcast(self, message): self.connection.privmsg(self.channel, message) def command(self, command): """decorator for callbacks to handle chat >commands""" def decorator(fun): self.commands[command]=fun return fun return decorator def connect(self, server, nickname, join_channel, password=None, port=6667): def on_connect(connection, event): connection.cap('REQ', ':twitch.tv/membership') connection.cap('REQ', ':twitch.tv/tags') connection.cap('REQ', ':twitch.tv/commands') connection.join(join_channel) if join_channel: self.channel=join_channel self.reactor.add_global_handler("welcome", on_connect) self.channel=join_channel coro=self.connection.connect(server=server, port=port, nickname=nickname, password=password) self.loop.run_until_complete(coro)
We create an IRC client now, and add callbacks for chat events:
loop = asyncio.get_event_loop() bot=AsyncIRC(loop) def run_once(loop): loop.call_soon(loop.stop) loop.run_forever() @bot.command("left") def command_left(connection, event): pygame.event.post( pygame.event.Event(pygame.KEYDOWN, key=pygame.K_LEFT, unicode=None, mod=None)) @bot.command("right") def command_right(connection, event): pygame.event.post( pygame.event.Event(pygame.KEYDOWN, key=pygame.K_RIGHT, unicode=None, mod=None)) @bot.command("up") def command_right(connection, event): pygame.event.post( pygame.event.Event(pygame.KEYDOWN, key=pygame.K_UP, unicode=None, mod=None)) @bot.command("down") def command_right(connection, event): pygame.event.post( pygame.event.Event(pygame.KEYDOWN, key=pygame.K_DOWN, unicode=None, mod=None)) @bot.command("newgame") def command_left(connection, event): pygame.event.post( pygame.event.Event(pygame.KEYUP, key=pygame.K_SPACE, unicode=None, mod=None)) @bot.handle("pubmsg") def on_pubmsg(connection, event): content=event.arguments[0] parse_tags(event) bot.msgs.append(f"{event.display_name}: {content}") print("#", bot.msgs)
The first five handlers translate chat commands into pygame events, while the last one takes every chat message and logs the logs the content into a list. This way we can display chat history in the game.
Now we can connect to the IRC like so:
bot.connect(server='irc.chat.twitch.tv', nickname=irc_user, password=irc_pw, join_channel="#"+irc_user)
and when we call run_once(loop), then the whole async IRC machinery will start looking for messages, handle them if there are any, and return.
Here comes the actual game part, based on wormy:
# Wormy (a Nibbles clone) # By Al Sweigart [email protected] # http://inventwithpython.com/pygame # Released under a "Simplified BSD" license # some IRC features added by Robert Pfeiffer import random, pygame, sys from pygame.locals import * FPS = 15 WINDOWWIDTH = 640 WINDOWHEIGHT = 480 CELLSIZE = 20 assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size." assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size." CELLWIDTH = int(WINDOWWIDTH / CELLSIZE) CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE) # R G B WHITE = (255, 255, 255) BLACK = ( 0, 0, 0) RED = (255, 0, 0) GREEN = ( 0, 255, 0) DARKGREEN = ( 0, 155, 0) DARKGRAY = ( 40, 40, 40) BGCOLOR = BLACK UP = 'up' DOWN = 'down' LEFT = 'left' RIGHT = 'right' HEAD = 0 # syntactic sugar: index of the worm's head def main(): global FPSCLOCK, DISPLAYSURF, BASICFONT, CHATFONT pygame.init() FPSCLOCK = pygame.time.Clock() DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) BASICFONT = pygame.font.Font('freesansbold.ttf', 18) CHATFONT = pygame.font.Font('freesansbold.ttf', 8) pygame.display.set_caption('Wormy') showStartScreen() while True: runGame() showGameOverScreen()
Here, CHATFONT was added to the original wormy game to display chat in a different font.
In the game loop, we added chat messages when a new game is started, and we now call run_once(loop) before clock.tick(), like in the previous examples. To make the game playable with streaming lag (chat will usually be way ahead of the stream), the variable keydown_this_frame will ensure that the game state is only advanced when either a key has been pressed, or a keypress has been sent over a chat command.
def runGame(): bot.broadcast("new game") bot.broadcast(">UP >DOWN >LEFT >RIGHT to play") # Set a random start point. startx = random.randint(5, CELLWIDTH - 6) starty = random.randint(5, CELLHEIGHT - 6) wormCoords = [{'x': startx, 'y': starty}, {'x': startx - 1, 'y': starty}, {'x': startx - 2, 'y': starty}] direction = RIGHT # Start the apple in a random place. apple = getRandomLocation() while True: # main game loop keydown_this_frame=False for event in pygame.event.get(): # event handling loop if event.type == QUIT: terminate() elif event.type == KEYDOWN: keydown_this_frame=True if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT: direction = LEFT elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT: direction = RIGHT elif (event.key == K_UP or event.key == K_w) and direction != DOWN: direction = UP elif (event.key == K_DOWN or event.key == K_s) and direction != UP: direction = DOWN elif event.key == K_ESCAPE: terminate() if keydown_this_frame: # BEGIN MOVEMENT CODE # check if the worm has hit itself or the edge if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT: return # game over for wormBody in wormCoords[1:]: if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']: return # game over # check if worm has eaten an apply if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']: # don't remove worm's tail segment apple = getRandomLocation() # set a new apple somewhere bot.broadcast("apple eaten") else: del wormCoords[-1] # remove worm's tail segment # move the worm by adding a segment in the direction it is moving if direction == UP: newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1} elif direction == DOWN: newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1} elif direction == LEFT: newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']} elif direction == RIGHT: newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']} wormCoords.insert(0, newHead) #END MOVEMENT CODE DISPLAYSURF.fill(BGCOLOR) drawGrid() drawWorm(wormCoords) drawApple(apple) drawScore(len(wormCoords) - 3) pygame.display.update() run_once(loop) FPSCLOCK.tick(FPS)
Logic to read IRC and run the event loop was added to the other game screens, and to the game termination function:
def terminate(): while len(asyncio.Task.all_tasks(loop)): run_once(loop) pygame.event.pump() loop.shutdown_asyncgens() loop.close() print("Thank you for playing!") pygame.quit() sys.exit() def getRandomLocation(): return {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)} def showGameOverScreen(): gameOverFont = pygame.font.Font('freesansbold.ttf', 150) gameSurf = gameOverFont.render('Game', True, WHITE) overSurf = gameOverFont.render('Over', True, WHITE) gameRect = gameSurf.get_rect() overRect = overSurf.get_rect() gameRect.midtop = (WINDOWWIDTH / 2, 10) overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25) bot.broadcast("game over") DISPLAYSURF.blit(gameSurf, gameRect) DISPLAYSURF.blit(overSurf, overRect) drawPressKeyMsg() pygame.display.update() pygame.time.wait(500) checkForKeyPress() # clear out any key presses in the event queue while True: run_once(loop) if checkForKeyPress(): pygame.event.get() # clear event queue return
In drawScore, we also draw the last 3 lines of chat. in a small font. This way you know how big the lag in the stream is, and whose last chat command is currently shown on the screen.
def drawScore(score): scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE) scoreRect = scoreSurf.get_rect() scoreRect.topleft = (WINDOWWIDTH - 120, 10) DISPLAYSURF.blit(scoreSurf, scoreRect) topleft=scoreRect.bottomleft for msg in bot.msgs[-3:]: IRCSurf = CHATFONT.render(msg, True, WHITE) IRCRect = IRCSurf.get_rect() IRCRect.topleft = topleft topleft= IRCRect.bottomleft DISPLAYSURF.blit(IRCSurf, IRCRect) def drawWorm(wormCoords): for coord in wormCoords: x = coord['x'] * CELLSIZE y = coord['y'] * CELLSIZE wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE) pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect) wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8) pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect) def drawApple(coord): x = coord['x'] * CELLSIZE y = coord['y'] * CELLSIZE appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE) pygame.draw.rect(DISPLAYSURF, RED, appleRect) def drawGrid(): for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT)) for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y)) if __name__ == '__main__': main()
This is the end of “twitch plays wormy”. You can copy all the segments into a python file together and run the game now. If you compare this code to the original wormy.py, you will see that it’s mostly the same, the changes are very limited - you can easily add the code to different games, as long as they aren’t quick-reaction-skill action games. If they are action games, you need to slow down the game to handle the lag. The code that reads chat only runs inside the event loop, so only when run_once(loop) is called, and interacts with the rest of the game by posting ordinary pygame events.
Tumblr media
That’s one rather famous type of twitch integration out of the way. But another type is far more common:
Twitch Voting
Most of the time, chat doesn’t play the game - the streamer plays it, and chat comments on gameplay or talks to the streamer. Chat integration is not about sending button presses to the game, or about moment-to-moment gameplay, but about asking chatters to help make occasional, high-level decisions: Which hat should I wear? Should I go left or right? Which card should I add to this deck?
So here is a simple poll/voting pygame app. It’s not integrated into an existing game this time. Asking twitch chat to vote on decisions is something that needs to fit into the game UI and overall game design, and I did not want to retrofit a complex game for this tutorial.
We start with the same imports:
import pygame import asyncio import irc, irc.client_aio import sys import collections # we need collections this time too if len(sys.argv)!=3: print("please get a twitch auth token from https://twitchapps.com/tmi/") sys.exit(1) username=sys.argv[1] token=sys.argv[2] irc_pw=token.strip() irc_user=username.strip() assert(irc_pw.startswith("oauth:"))
This time, the AsyncIRC class is more complex. In addition to a handler for chat commands, there is also a handler for poll votes. In addition to a list of chat messages, there are also fields for counting votes, counting voters, voting options, and so on.
def parse_tags(event): if hasattr(event,"tags_dict"): return event.tags_dict tags={} for tag in event.tags: tags[tag["key"]]=tag["value"] event.tags_dict=tags try: event.display_name=tags["display-name"] except: pass class AsyncIRC(object): def __init__(self, loop, command_prefix=">", poll_prefix="#"): self.loop = loop or asyncio.get_event_loop() self.reactor=irc.client_aio.AioReactor(loop=self.loop) self.connection=self.reactor.server() self.commands=dict() self.command_prefix=command_prefix self.poll_prefix=poll_prefix self.msgs=[] self.has_voted=[] self.poll_votes=0 self.poll_count={} self.poll_options=[] self.poll_running=False def dispatch_cmd(connection, event): content=event.arguments[0] if content.startswith(self.command_prefix): sans_prefix=content[len(self.command_prefix):] try: cmd, *args = sans_prefix.split() except: cmd = sans_prefix args=[] cmd=cmd.lower() if cmd in self.commands: parse_tags(event) return self.commands[cmd](connection, event, *args) else: print('invalid command: ' + cmd) def count_poll(connection, event): content=event.arguments[0] if self.poll_running and content.startswith(self.poll_prefix): sans_prefix=content[len(self.poll_prefix):].strip().lower() if sans_prefix in self.poll_options: if not event.source in self.has_voted: self.poll_count[sans_prefix]+=1 self.poll_votes+=1 # self.has_voted.append(event.source) #commented out for testing #so you can vote twice self.reactor.add_global_handler("pubmsg", dispatch_cmd, -1) self.reactor.add_global_handler("pubmsg", count_poll, -1) def start_poll(self, title, options): self.poll_votes=0 self.has_voted=[] self.poll_count=collections.defaultdict(int) self.poll_options=[str(option).strip().lower() for option in options] self.poll_running=True self.poll_title=title message=f"Poll: {title} - " message+=", ".join([self.poll_prefix+option for option in options]) self.connection.privmsg(self.channel, message) self.connection.privmsg(self.channel, "voting starts NOW") def stop_poll(self): self.poll_running=False best_option=None for option in self.poll_options: if self.poll_count[option] > self.poll_count[best_option]: best_option=option nvotes=self.poll_count[best_option] percent=int(100*nvotes/self.poll_votes) message=f"poll {self.poll_title} ended - {best_option} won with {nvotes} votes ({percent}%)" self.connection.privmsg(self.channel, message) def handle(self, event_type, *args, **kwargs): def decorator(fun): self.reactor.add_global_handler(event_type, fun, *args, **kwargs) return fun return decorator def broadcast(self, message): self.connection.privmsg(self.channel, message) def command(self, command): def decorator(fun): self.commands[command]=fun return fun return decorator def connect(self, server, nickname, join_channel, password=None, port=6667): def on_connect(connection, event): connection.cap('REQ', ':twitch.tv/membership') connection.cap('REQ', ':twitch.tv/tags') connection.cap('REQ', ':twitch.tv/commands') connection.join(join_channel) if join_channel: self.channel=join_channel self.reactor.add_global_handler("welcome", on_connect) self.channel=join_channel coro=self.connection.connect(server=server, port=port, nickname=nickname, password=password) self.loop.run_until_complete(coro) loop = asyncio.get_event_loop() bot=AsyncIRC(loop)
Again, we log all public messages.
@bot.handle("pubmsg") def on_pubmsg(connection, event): content=event.arguments[0] parse_tags(event) bot.msgs.append(f"{event.display_name}: {content}") #print("#", bot.msgs) bot.connect(server='irc.chat.twitch.tv', nickname=irc_user, password=irc_pw, join_channel="#"+irc_user) def run_once(loop): loop.call_soon(loop.stop) loop.run_forever()
The actual UI for this twitch polling app is rather short. When the user presses Return, the poll starts, if it isn’t already running. The duration of the poll is set by the variable poll_ticks in the game loop, not in the event loop. While the poll hasn’t been stopped, it keeps on counting on the event loop.
Since the vote counting happens only inside run_once(loop), there are no race conditions between polling and game loop, and we don’t need to worry about race conditions for votes that arrive just as the poll ends, or votes that arrive while the UI is being drawn.
poll_ticks=-1 my_options=["A", "B", "C"] pygame.init() screen_size=640,480 screen=pygame.display.set_mode(screen_size) clock=pygame.time.Clock() running=True flying_frames=0 best=0 color=(50,50,50) font=pygame.font.SysFont("Helvetica Neue,Helvetica,Ubuntu Sans,Bitstream Vera Sans,DejaVu Sans,Latin Modern Sans,Liberation Sans,Nimbus Sans L,Noto Sans,Calibri,Futura,Beteckna,Arial", 16) while running: clock.tick(30) events=pygame.event.get() for e in events: if e.type==pygame.QUIT: running=False if e.type==pygame.KEYDOWN and e.key==pygame.K_RETURN: if poll_ticks<=0: bot.start_poll("Test Vote", my_options) poll_ticks=30*45 #FPS*45 seconds screen.fill((255,255,255)) if poll_ticks>=0: if poll_ticks>0: poll_seconds=poll_ticks//30 time_text=font.render(f"{poll_seconds}s remaining", True, (0,0,0)) else: time_text=font.render("results:", True, (0,0,0)) screen.blit(time_text,(10,30)) for i, option in enumerate(bot.poll_options): nvotes=bot.poll_count[option] if bot.poll_votes>0: percent=int(100*nvotes/bot.poll_votes) else: percent=0 option_text=font.render( f"{bot.poll_prefix}{option}: {nvotes} ({percent}%)", True, (0,0,0)) y_pos=100+i*30 screen.blit(option_text,(10,y_pos)) if bot.poll_votes < 20: bar_length=nvotes*20 else: bar_length=percent*5 pygame.draw.rect(screen, color, pygame.Rect(100, y_pos, bar_length,25)) if poll_ticks>0: poll_ticks-=1 if poll_ticks==0: bot.stop_poll() fps=clock.get_fps() pygame.display.update() run_once(loop) while len(asyncio.Task.all_tasks(loop)): run_once(loop) loop.shutdown_asyncgens() loop.close() print("Thank you for playing!")
Now you can add voting to your own pygame games. Maybe you shouldn’t call the options “1”, “2”, and “3”, but give them descriptive names depending on the current situation.
Tumblr media
1 note · View note