Build Up To Boston: Demo Changes

Hi all!

I hope you had an awesome labor day holiday. I spent my Sunday at the US Open watching some awesome tennis and getting an awesome tan. I now take regular and needless coffee breaks at the office so I can show it off.

This week I’m posting every day, building up to the Boston Festival of Indie Games! Last year the FIG had over 7,000 attendees. It’s a staggering thought that even 1/10th of those people might check out Vidar, and I can’t thank the program coordinators and curators enough for accepting my game into the showcase. So without further ado, today I want to talk about what’s changed since NYC Games Forum?

You might recall that the first time ever someone could play Vidar was at the end of July, at the NYC Games Forum playtest night. We had about 20-25 people play it, and got some awesome feedback. All of it and more has been incorporated in just the 6 weeks since.

New Art

The most immediate change has been all new art. Becca Bair‘s sumptuous tiles and sprites now dominate the game. When it comes to maps, this means that the cave feels more, well, cave-like. Rounded edges instead of square ones, organic walls, and a desaturated tint all help immerse the player even more.

Out with the old, in the with desaturated.

Out with the old, in the with desaturated.

And of course, Becca’s also prepared new sprites. The cast of characters the player can interact with have all been replaced (as has the player sprite itself). These taller sprites have more detail and, as a result, more character. You can get to know them a little better just by looking at ’em.

Vidar is, at its core, about the people. Which means the people better be damn good to look at.

Vidar is, at its core, about the people. Which means the people better be damn good to look at.

New Content

Since I was going to add these new sprites, I wanted to make sure the characters mattered. In the NYC Games Forum Demo, players could talk to Vidar’s citizens but, short of seeing some dialogue, it didn’t change the demo itself. The player was always going to try to rescue Sandor’s son. Now there are two big options – Sandor’s son is still in the game, but there is a chance the player will instead see Room 2 of the Ice Cave. Room 2 is a series of 3 puzzles, and there are a handful of quests that can spawn there. Specifically:

  • If Bernadett is alive, she’ll ask the player to return a ghost’s spirit to its grave
  • If Borbalo is alive and the player has Bernadett’s quest, Borbalo will ask the player to bless the grave with holy water
  • If Dani is alive and Borbalo is dead, Dani will ask the player to find Borbalo’s alcohol
  • If Szabina is alive, she’ll ask the player to find a clue to the Beast’s origins in the cave
  • If Lilja is alive and Szabina is dead, Lilja will ask the player to dig around in the cave for buried treasure
  • If Sandor is alive, he’ll ask the player to go rescue his son

As you can see, some of the quests included are mutually exclusive; this means that the two NPCs chosen to die at the beginning have immediate consequences for the demo.

Most of the quests are handed out at the inn, where Vidar's citizens have congregated for this demo. But the workshop is also open.

Most of the quests are handed out at the inn, where Vidar’s citizens have congregated for this demo. But the workshop is also open.

The game decides where to send the player based on whether they got Sandor and/or Bernadett’s quest. If the player received only one, they’ll go to the map which has that quest. If they got both, it’s randomly chosen. As a result, I’ve rigged the demo’s random deaths a little bit – Sandor and Bernadett can’t both die in any playthrough of the demo.

Sandor’s Son

At NYC Games Forum, I got a lot of feedback about mechanics, balance, and puzzle-solving. So all of the following changes have been made to Erik’s room:

  • Players will only solve either the left side or the right side of the room, as opposed to both from NYC Games Forum. The “left side” involves rotating arrows with the Stranger to guide Erik to the exit. The “right side” involves opening and closing doors with the Stranger to guide Erik to the exit. If the player is sent to this map, which side they do is also chosen at random.
  • Additional options have been added to both sides. What this means is three levels of chance – a player has a chance to go to Erik’s room, a chance to play the left side, and a chance to see any one of 5 puzzle options in the left side.
  • Pressing “A” to switch between Erik and the Stranger is instantaneous, instead of fading the screen out and back in again.
  • When ice breaks around Erik, it no longer pauses the game. Combined with the above, players will (hopefully) no longer be frustrated that time is passing by because of things outside their control.
  • The graphics for the gates in this puzzle are now clearly gates, and not spikes which suggested to players that they should not run into them.
  • The tutorial has a more fulsome explanation of sliding, pressing “A” to switch characters, and using switches.
  • Compass arrows have been added (described below)
  • There is a cutscene if the player fails to save Erik, rather than just simply fading out the demo and concluding.
Gates which are clearly gates!

Gates which are clearly gates!

After playing this new version of the Sandor’s Son quest, I’m in love with all of these changes. And that tells me that NYC Games Forum Playtest Night did its job; I really can’t thank the playtesters enough for their incredibly valuable and candid feedback. It’s already improved the game 10 fold.

Compass Arrows

A few people at NYC Games Forum indicated that they didn’t know what the goal was in any given puzzle. Specifically, where’s the exit? Where am I trying to go? So with this version of the demo, I’ve added compass arrows. These little indicators bounce up and down where you’re supposed to go next in the puzzle, and intelligently do so based on where you’ve been.

Four exits? No longer a problem, just head north towards that arrow.

Four exits? No longer a problem, just head north towards that arrow.

The arrows disappears after you go over it once. Presumably, by then the player will know where the exit is. While compass arrows will be turned on in the demo, they’ll be a quest reward in Vidar. Every possible item which changes your gameplay experience – from sprint shoes to extra time to the clock itself – is a quest reward, and there’s no reason to treat the arrows any differently.

Additional Changes

A few other fun things have been added. The player can interact with certain items in town for flavor text. More branching paths are explained at the end of the demo. The menu has been cleaned up to remove items not available in the demo. More puzzles have been color coded. And of course, dozens of bugs have been cleaned up.

I’ll have 4 laptops running the demo at Boston FIG from 10 am till close. The event is this Saturday, September 13 at MIT. If you’re in the Northeast, it’s not to be missed!

Finally, don’t forget to sign up for email updates about Vidar on the website. If you sign up before Saturday, you’ll be entered to win a Vidar-embroidered beanie!

Advertisements

Transfer Lock

Double-post today! Reddit user tilfordkage wanted to block a player from advancing to a new area until the player reached a certain level. This is an easy solution!

Make Your Party Level Variable

In any event, create a event command of the type “Control Variable.” You’ll be greeted by this screen (it won’t be filled in).

Use this window to set variables as you need.

Use this window to set variables as you need.

To get your window filled in like this, click on the … on the top line to name your variable (here, I did Player Level but it doesn’t matter). Select the Game Data radio button below, click …, and fill in the screen that pops up like this:

You can set the variable to a whole host of things about a player character, including their ATK, their current HP, or here, their level.

You can set the variable to a whole host of things about a player character, including their ATK, their current HP, or here, their level.

Now, every time we trigger our event, we’ll first set Variable 1 to Eric’s level.

 

Make The Rest Your Event

The rest is easy! Transfer events are almost always below characters/player touch so make sure your priority and trigger options in the bottom left are set accordingly. Then in the logic, after we set our variable, put in a conditional branch. If variable 1 >= 10, transfer. Otherwise, move the player away from the event and tell them to get a few more levels already!

Here we say to move the player down if he can't transfer, but use your judgment to replace the player accordingly.

Here we say to move the player down if he can’t transfer, but use your judgment to replace the player accordingly.

 

Multiparty

Worried that the player’s just power-leveled one actor and not the others? Average out the levels! Just do the math on the variable before the conditional branch.

Use control variable over and over to modify the event. Make sure to use the operators on the variable, don't just reset it!

Use control variable over and over to modify the event. Make sure to use the operators on the variable, don’t just reset it!

Good luck, tilfordkage!

Friday Script Or Not – Fomar’s Skill Master / Learn By Doing

If you want to get the most out of RPG Maker, learn Ruby. In the meantime, lots of talented scripters have done the work for you. Every Friday, The Iron Shoe features a fun script and goes into detail about how to use it. It also covers a little bit of Ruby each time so you can make even more out of the script.

Everyone loves to make their RPG stand out just a little bit, and one amazing way to do that is with a unique skill system. Today I want to talk about one option – a learn-by-doing system where you increase your skill ability based on the number of times you’ve used it! This is a Friday Script post, and we’ll delve into Fomar’s awesome and succinct Skill Mater scriptBut first, we’re going to do it all without scripts. In fact, you can make this system with events alone.

Skill System By Events

There are a few basic components we need to create in the database. The first is, for every skill that can be leveled, we need a variable corresponding to each actor that can use it. Based on your game design, this could be a lot of variables! You’ll need one final variable that the ID of the caster. Make a note of which one that is (here, 16)

Multiple actors could have access to the same skill - or not! Whatever you want!

Multiple actors could have access to the same skill – or not! Whatever you want!

The second is to build the skills, as many levels of them as we want. So, if we want “Spin Attack I”, “Spin Attack II”, and “Spin Attack III,” we make each skill with higher damage amounts, higher MP costs, etc.

Learn By Doing

Skills can do more than one thing. Just use the ; to separate lines of code.

Note that in my damage formula box, I have a normal damage formula, followed by:

; $game_variables[16] = a.id

Variable 16 is my Caster ID variable. What I’m asking the damage formula box to do is first deal damage, then set the variable to who is casting. We’ll use this in the next step. It’s important that every skill that you want to level has this little line after it’s damage formula. You can copy and paste it – it’s the same variable, same everything for every skill.

Third, we make a common event for each skill that’s going to be leveled. One for Spin Attack level, one for Fireball, etc. In each one, we’ll need to take yet another variable that represents which actor cast the spell, and based on that, increment the correct variable. We’ll also need to ask if that variable is above a certain threshold – if it is, our actor should learn the new, powerful level of the skill! (and take away the weaker one if you’d like).

You'll need one for every chain level of skill, and nesting options for each actor that could use that skill.

You’ll need one for every chain level of skill, and nesting options for each actor that could use that skill.

Let’s walk through the logic of this common event. We have a series of conditional branches which ask “who is the casting actor?” If it’s 1, then increase the skill variable assigned to that actor by 1. If that brings us to 50 or above, ask if Eric’s already learned the next step. If he has, do nothing. If he hasn’t, teach it to him.

And finally, in each of our skills, we need to set the casting actor variable, and call our leveling common event.

Remember to make sure you've already set the caster ID!

Remember to make sure you’ve already set the caster ID!

It’s pretty easy logic, but is extremely tedious. We need potentially dozens of variables, numerous common events. To simplify, we can use Fomar’s script. Download and install it, and open it up. All of our work happens in that script.

Skill System By Script

From above, we still need to keep all of the different skills. So our skill table in the database will be quite long. But we don’t need the variables and we don’t need the common events.

Look for this area in Fomar’s script:

When you get here, delete the example SKILL[3] line. Otherwise you'll end up with something wonky.

When you get here, delete the example SKILL[3] line. Otherwise you’ll end up with something wonky.

There, we’ll add all of our leveling skill scripts. We do it like this:

SKILLS[original] = [new, uses, replace]

We’ll replace the terms original, new, and uses with numbers. And we’ll replace ‘replace’ with true or false. Specifically:

  • “Original” is the id of the skill being used. So for our Fire I, it’s 9
  • “New” is the id of the next level skill. Fire II’s id is 10
  • “Uses” is how many uses it takes to get from the original skill to the new skill. Choose what you’d like.
  • “Replace” is either true or false – if it’s true, the new skill replaces the old; if false, the new skill is added to the list without altering the old.

We list each skill that has the possibility to “evolve” so-to-speak, and separate them with new lines. Something like this:

Using # in our code means anything we type after on that line has absolutely no impact. It's called a "comment," and I use it here to keep track of what each line is doing. Make sure to keep your games organized!

Using # in our code means anything we type after on that line has absolutely no impact. It’s called a “comment,” and I use it here to keep track of what each line is doing. Make sure to keep your games organized!

Beginner Challenge

Sometimes, it’s nice to have branching paths in our skill tree. We also occasionally let players keep a set of earlier skills because, while they do less damage, they cost less, and the strategy inherent in that decision is more interesting than just always blasting away with the highest level fireball. Using Fomar’s script, how can we make our Fire I spell teach you Fire II after 25 uses, but also teach you Fire All after 50 uses (encouraging you to use Fire I even after you get the upgrade)?

Advanced Challenge

There are two classes an actor can be – Witch and Spellsword. Both can cast Fire, and Fire upgrades to Fire II and Fire III. But the Spellsword takes twice as many uses as the Witch does. Using events, how can we achieve this?

We’ll discuss answers in a few weeks!

Dev Blog – Switches 1

I thought it worthwhile to do a series on how Switches are handled in Vidar. In this series, when I use the capitalized-S Switches, I’m not talking about those numbered global booleans that you can access in the trigger editors. I’m talking about things you interact with that you expect to do something, like these:

To make matters more confusing, these are called "Switches" in the RTP Character Sheets.

To make matters more confusing, these are called “Switches” in the RTP Character Sheets.

I’ll use the lowercase-s switch to refer to the boolean that you set. Any basic dungeon will end up having a Switch like the one above that opens a door. And it’s easy to have an event page for your Switch look like this:

This is typically accompanied by a page 2, which has as its condition, "Open Door 1"

This is typically accompanied by a page 2, which has as its condition, “Open Door 1”

And then your door would have 2 pages; one where the door is closed, one where it’s open and the conditional is that “Open Door 1” switch. And then you’ll use another switch in another Switch for “Open Door 2,” and another for “Open Door 3…”

This is a bad habit. Stop doing it.

What you’re doing is creating global booleans that only get used once. Not only are you cluttering your list of switches, there’s a strong chance you could accidentally call it with something else, a chance that something gets moved or deleted. Once you have more than 10 doors, you’ve got a headache. These switches are really good for massive plot-moving periods in your game, because they’re an easily referenced marker – use switches for things like “Cave Boss Defeated” or “Fire Summon Available.” Don’t use them for Switches and Doors.

Vidar in particular can’t use switches like this. Why?

  1. There are hundreds of possible doors in Vidar, making tracking them tedious
  2. Which doors are actually spawned at the beginning of the game are chosen randomly, making tracking them really tedious

Plus, it’s bad practice. There’s a much better way. For the second page of your door, instead of using a global switch, use a self-switch. Something like this:

Now your door isn't dependent on some switch in your list that you might accidentally click; it's dependent on its own self-switch.

Now your door isn’t dependent on some switch in your list that you might accidentally click; it’s dependent on its own self-switch.

As it turns out, your Switch can tell the door to turn on its own self-switch. Just use this:

$game_self_switches[[mapid, eventid, "A"]] = true

So instead of using one of those global switches, our Switch page would just look like this:

Since we're not using a global switch, we need to trigger 2 self-switches; the door and the Switch itself.

Since we’re not using a global switch, we need to trigger 2 self-switches; the door and the Switch itself.

Why is this so desirable? Because it’s flexible. We can replace all of those variables dynamically. We can run this thing through a for loop. We can have dynamic control over every door.

So, for example, if we have a room with a puzzle that has 100 doors, we could do something like:

100.times {|i| $game_self_switches[[5,i,"A"]]= $game_self_switches[[5,i,"A"]]? false : true}

which would “toggle” all 100 doors – open all closed ones, close all open ones. With one line of code, and not 100  event calls, nested in if-then statements. And without 100 different switches in our global switch list, which we have to navigate for months to come. Even if you’re not going to do something in-depth, you can easily clean up your game using this method instead of one-off global booleans.

This is the starting point for Switches in Vidar. There’s obviously a lot more – Switches do different things depending on the puzzle they’re in, and having them know what function to call is its own can of worms, but we’ll save that for another day.

Bookshelves – Dev Blog

Super excited about this new puzzle in Vidar. Should you come across a library, you’ll find books all over the place and all out of order. If you place those books in the right place, something quite awesome will happen. I want to show you how I’m handling the bookcases.

To do this, I used a few variables:

  • One for each bookcase – this will hold the item ID of the book currently on the assigned bookcase
  • One titled “Book to Place” – this will hold the item ID of the book we’re able to place
  • One titled “Bookshelf Being Tested” – when you interact with a bookcase, it places it’s number in this variable
  • One titled “Tested Case’s Value” – this looks up what’s current on the shelf you’re interacting with

I also use Yanfly’s Message Manager – a Friday script feature will certainly follow, but I’ve been giving Yanfly a bit too much of the spotlight around here recently 😉 The only use here is to be able to reference an item name easily.

Nearly all of this is handled by a common event. Here it is:

Ignore the stuff below, it's just there to handle what happens when you try to put your journal on the bookcase. It doesn't belong there!

Well, almost all of it. Ignore the stuff below the cut-off, it’s just there to handle what happens when you try to put your journal on the bookcase. It doesn’t belong there!

The first line finds out the number stored in the variable associated with that particular bookcase. If the number is greater than 0, it means there’s already something on the bookcase! So, we tell the player that the item is on the bookcase, and ask if they want it. If so, we give it to them, and set the value of the shelf to 0.

If the number’s not greater than 0, we use RPG Maker’s built-in “”Select Key Item” command to allow the player to chose a book from their inventory. That book then gets removed from inventory, and the variable associated with that case is changed to the book’s item ID.

There’s one more step in the equation. The case itself.

This is the actual event the player interacts with. Put it on the bookcase!

This is the actual event the player interacts with. Put it on the bookcase!

This is the event you interact with, and it needs a bit of explaining. The first line is just flavor text. In the second line, we set Bookshelf Being Tested to a number. That number is the variable ID for Case 5.

 

As noted at the top, every case gets its own variable.

As noted at the top, every case gets its own variable.

In every bookcase, we set Bookshelf Being Tested to the correct variable ID. So, if we were testing Bookcase 8, we’d set the variable to 55. What this does is allow our common event to ask “what variable am I supposed to check to see if there’s an item on this particular bookcase?”

We call the common event, and it handles the rest of the logic.

 

So Many Pieces – Challenge Solution

A few weeks ago I issued a challenge: populate your game with three different-colored chests, and to open then, require a player to have 50 fragments of the right color of key. We solved a single key problem all within the chest event, but here I asked you to do it with a common event that runs each time a chest is opened.

Why? Well, what if you find that 50 key fragments are just way too many to ask a player to get, and want to change it to 10 for your entire game. If you have any more than a dozen chests, you’re going to curse the day you decided to have all of that information contained in each chest event.

And we’re going to solve the problem with Ruby. Don’t be afraid! This one is easy. So let’s get to it! I’ve created three items in my database, one for each key fragment, and they are items 4, 5, and 6 (you can check for your item IDs in the game Database, it’s the number to the left of the item name). Red, blue, and green, respectively. I also need a variable, a switch, and a common event.

  • I call my variable “Key to Check” – this is different than before, when we wanted to know how many of an item the player had in their inventory. Instead, we’re storing in this variable the item ID for the chest. 4 for red, 5 for blue, you get the idea.
  • My switch is named “Chest Can Open” – if it’s on, the chest will open. If it’s off, the chest will remind us we need more key fragments.
  • My common event is called “Open Chest Check” – it’s the event that will process all chests and decide whether to open them.

I’ll set up my chest with a conditional branch, just as we did before. It’s just that the things we do in advance are a little different. We’ll need to set our “Key to Check” variable based on the color of our chest, and then we’ll need to call our common event. Finally, the conditional branch is based on our switch. Like so!

To think only a few weeks ago we were pickle hunting in this forest.

To think only a few weeks ago we were pickle hunting in this forest.

Note that because it’s a red chest, the Key To Use is set to 4 – the item ID of my Red Key Fragment. Now we build our common event. Choose “script” from the trigger editor to open a scripting window, and add the following.

Just a few lines of code will process all of our chests in the game.

Just a few lines of code will process all of our chests in the game.

Ok, let’s go through that line by line:

  • id = $game_variables[5] : here, we’re just setting whatever the value is in our “Key To Use” to an easy name, “id.” The script editor inside a common event doesn’t play nicely when you don’t name your variables.
  • key = $data_items[id] : now that we have our id, it’s easy to actually match the id up to an item. We’ll call our item “key” (even though it’s really a fragment, we don’t win points for being literal).
  • itemamt = $game_party.item_number(key) : a built-in RPG-Maker function, this allows you to find out how many of a given item the party has. In this case, we’re “giving” it key, which we defined in the line before.
  • if itemamt >= 50 : this is just like a conditional branch in the trigger editor. We’re asking, if the player has 50 or more of whatever item we’ve chosen.
  • $game_switches[1] = true : set our “Chest Can Open” switch to ON
  • $game_party.lose_item(key, 50) : another awesome built-in, we tell RPG Maker which item to lose (here, it’s “key”) and how many to lose (here, “50”)
  • else : just like the else in conditional branches in the trigger editor
  • $game_switches[1] = false : set our “Chest Can Open” switch to OFF
  • end : make sure to end your if/else statement

And that’s it! Doing it this way has two VERY nice features:

  • If you want to change the amount of key fragments from 50 to 10, you only have to change it in two places. You can probably tell where they are in the script!
  • If you want to add a yellow chest, no problem! No need to reprogram anything, just make a yellow key fragment and you’re off to the races – this common event doesn’t care what chest you’re opening.

Happy scripting!

 

 

Class Warfare

Reddit user kraegar wanted the player to choose 2 class for her party at the start of the game, but wanted to prevent her from duplicating the first class. The set-up was simple: in room 1, the player encountered 10 NPCs each representing a class, and the player would chose one for her first party member. In room 2, she encountered 9 NPCs – the classes, with the already-chosen one conspicuously absent. Kraegar set Variable 1 “Player 1 Class” to a number, 1-10, based on what you picked, and Variable 2 “Player 2 Class” the same. But how to make the NPC in room 2 disappear, as oppose to tell you “Sorry, you’ve already chosen my class?”

The answer is event pages!

First, let’s set up our first room, with all ten classes. When you talk to the NPC, we’ll give the player a choice to accept that class, and then if they do, assign the variable accordingly. Set up your event page like this:

We set variable 1 to "6" to represent healer. Just make sure you remember the numbers for each class!

We set variable 1 to “6” to represent healer. Just make sure you remember the numbers for each class!

 

We might even make every NPC tell you to advance to the next room once you’ve chosen a class. Let’s get comfortable with using different event pages. Once you’ve set up your NPCs, click “New Event Page” at the top, and for that page set it up something like this (I chose a different class this time – you’ll want each event to only deal with a single class).

The circle indicates what the page's number is. Number is critical to determining order.

The circle indicates what the page’s number is. Number is critical to determining order.

A few notes here. Sure, we could’ve put all of this in one event page, but in order to change the dialogue depending on your class we’d need nesting conditional branches. As you get more complex with your events, these conditional branches can run right out of the window, and can make it incredibly difficult to follow your event logic. Where possible, use event pages!

Second, it’s important that this event page be numerically higher than the previous one. That is, the page when you’ve already made a choice cannot be number 1, while the page prompting you for your choice is number 2. Why?

RPG Maker always displays the highest numbered event page where all of the conditions are true.

So long as Player 1 Class is 1 or above, this second page will be on display. If we flipped them, our prompt page would be on display no matter what – it has no conditions! Any page with a lower number would never be displayed.

Ok, we’ve chosen our class, and we’re well on our way. It’s surprisingly simple to set up the next room. The only difference is that we need a few event pages! The first will be the nearly the same as before – copy and past from your old room, just change the text and variable setting to reflect that this is your second choice.

If you only want to copy a page, and not the entire event, there's a button for that.

If you only want to copy a page, and not the entire event, there’s a button for that.

Now, we want our Bard to show up in this room only if Variable 1 is not equal to 9. As you might’ve guessed, make a new event page. This time, set the condition to “if Variable 1 is 9 or above” and leave the entire thing – graphic and all – blank. Like so:

Make sure blank event pages like this one are set to "Below Characters" - otherwise, you'll create an invisible wall.

Make sure blank event pages like this one are set to “Below Characters” – otherwise, you’ll create an invisible wall.

But wait, what if Variable 1 is 10 – the pugilist? We solve it with, you guessed it, another event page. Copy and paste the first one, into slot three, and set the condition to Variable 1 is 10 or above.

Our Bard is rather full of himself, isn't he.

Our Bard is rather full of himself, isn’t he.

And that’s it! Now when you enter this room, if Variable 1 is equal to 9, you won’t see the Bard. We can do the same for all of our classes, to have a seamless class picking setup.

A Little Ruby

Don’t be scared of learning how to script in RPG Maker a little at a time! While this approach works for some, you may have reasons for not wanting to store a class ID in a variable. Oftentimes in complicated games, you can end up with thousands of switches and variables, and so just grabbing the class ID of a character is preferable to accessing a variable. We can do this! To get the class of any given actor, you use:

$game_actors[actor_id].class_id

This will get you the class id of the actor identified. You can find both of the numbers in your game’s database. While event pages don’t have script conditions built in, this can still be a powerful tool to use.

Once it's a script, we can start to dynamically change a lot of things. We can even change a party member's class on the fly.

Once it’s a script, we can start to dynamically change a lot of things. We can even change a party member’s class on the fly.