Lich:Script foreach: Difference between revisions

The official GemStone IV encyclopedia.
Jump to navigation Jump to search
(Created page with " {{Third-Party Software}} Category:Third-Party Software {{top}}")
 
(additional documentation)
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{3rd-party}}
=== What is it? ===

foreach is a script for sending a series of commands for each item that matches its criteria.

While not a full replacement for "proper" purpose-built Lich scripts, it is still frequently useful in its own regard. Anywhere you would otherwise repeat the same handful of commands once per item -- moving boxes, cutting gems, reading scrolls, selling for a bounty -- foreach can do it in a single line.

=== I don't want to read docs, can you give me some examples? ===

No rogues around? Move all your boxes to your locker:
`;foreach box in inv; move to locker`

Move all your boxes back out of your locker:
`;foreach box in locker; move to backpack`

Own a gemcutter and want to cut all the gems in a container?
`;foreach gem in red sack; move to gemcutter; turn gemcutter; waitrt; move to blue sack`

Getting boxes picked?
`;foreach box in inv; get item; give item to Rogue; waitfor Rogue offers you; accept item`
*(This'll only work if you're fast enough to empty boxes while the rogue is picking)*

Checking for orb gems?
Sorcerer: `;foreach gem in queue bag; get item; waitmana 4; prep 704; cast item; pause; put item in reject bag`
Bard using `;loresing`: `;foreach gem in queue bag; get item; waitfor You remove; waitmana 20; ;loresing purpose noun; pause; waitrt?; put item in reject bag`
While the script is paused, put the gem in the orb bag if it's an orb. `;unpause` will put it in the reject bag if you're still holding it.

Bulk reading scrolls?
`;foreach scroll in inv; read item`

Appraise every gem in a container (foreach gets each one, appraises it, and puts it back):
`;foreach gem in backpack; appraise`

Accidentally move a bunch of items to the wrong container using foreach?
`;foreach in last; move to container` *(back where they started)*
*or* `;foreach in last; get item; move to correct backpack`

Turning in gems or herbs for a bounty?
`;foreach name=uncut diamond in inv; get item; sell item`

Don't want to sell ALL of your diamonds for said bounty?
`;foreach first 7 name=uncut diamond in inv; get item; sell item`

Sell everything in a container that the local pawnshop will buy:
`;foreach sellable=pawnshop in my cloak; get item; sell item`

Doing a long task and want to be able to resume it later (possibly on the same source container)?
`;foreach unmarked gem in wherever; get item; do lots of things; mark item; return` as many times as needed, followed by
`;foreach marked gem in wherever; get item; unmark item`
(`wherever` must be a container in your inventory or your entire `inv`)

Need to ditch your sorcerer wands but want to keep the wizard ones?
`;foreach q=/(bloodwood|twisted|yew|bone|glass|thanot) wand/ in inv; sell`
(This uses regular-expression pattern matching -- note the slashes.)

Match a specific full name (article and adjectives included):
`;foreach name=*quartz orb in inv; get item; put item in locker`


=== That's nice. But what can it REALLY do? ===

== Usage ==
;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**;** _command1_**;** _command2_**;** ...]
;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**/** _command1_**/** _command2_**/** ...]
;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**|** _command1_**|** _command2_**|** ...]

Typing `;foreach` or `;foreach help` by itself prints the built-in help, including the live list of item types and sellable categories that Lich currently knows about.

== Options ==

_options_ is a set of optional filters on what matching items `foreach` will operate on. It can consist of zero or more
of the following:

**registered** _or_ **unregistered**
Only matches items that are registered or not registered. This option is only available if the items in question
are in your inventory or your premium locker. (`locker manifest` is used to determine item status in the latter case,
which is not available for standard lockers.)

**marked** _or_ **unmarked**
Only matches items that are marked or not marked as unsellable. This has the same restrictions as the above.
You can use this in conjunction with MARKing items as part of your ;foreach script to prevent operating on the same
item more than once in situations where you might run ;foreach multiple times.

**unique**
Only the first item with any given full name will be matched. This is global across all containers, so if you have
the same item in two different containers only the first item (whichever `foreach` sees first) will be matched.

**first _N_**
Stop after _N_ matching items have been encountered. (The word `first` is optional, so `;foreach 5 gem ...` works.)

**skip _N_** _or_ **after _N_**
Skip the first _N_ matching items.

**sort** _or_ **sorted**
Sort items by full name within each respective container. Articles "a", "an", "some" and "the" are ignored when
sorting. Containers are still handled one at a time, and the order of the containers themselves is not affected.

**nounsort** _or_ **nsort** _(also_ **nsorted** _/_ **nounsorted**_)_
Sort items by noun first, then by full name, within each respective container. Useful when you want all of one kind
of item grouped together regardless of adjectives. As with **sort**, articles are ignored and container order is
unaffected. (**sort** and **nounsort** are mutually exclusive -- specify at most one.)

**reverse** _or_ **reversed**
Reverse the order of items within each container. If used alone, this means the last item in each container is
processed first and vice versa. If used with **sorted** (or **nounsort**), items are handled in descending order
rather than ascending. Containers are still handled one at a time, and the order of the containers themselves is not
affected.

Options are applied roughly in the order listed above. You can combine **first** with **skip**:
`;foreach first 5 after 10` will match items 11 through 15.

== What ==

_what_ allows you to filter the types of items `foreach` acts on. It can be one of the following:

**type=**_pattern_ or **t=**_pattern_ or simply _pattern_
You can specify any type of item that Lich knows about. Examples include 'gem', 'wand' and 'scroll'
(which includes things like palimpsests and other 'alternate names' for scrolls). `;foreach` by itself will show
all the known types. `;foreach in inv` with no commands will show the types of all items it finds.

You can use `type=none` (or `type=unknown`) to explicitly find items that have no defined type according to Lich.

**Note:** This is only as accurate as Lich's own type data. You may be able to get more accurate type data by
downloading and running the `gameobjadd` script at startup, or by keeping `gameobj-data.xml` up to date.

**sellable=**_pattern_ or **s=**_pattern_
You can match items by which shops will buy them, based on Lich's sellable data. For example,
`;foreach sellable=pawnshop in my cloak; get item; sell item` will sell everything the pawnshop accepts.
Use `sellable=none` (or `sellable=unknown`) to match items with no known sellable category.
`;foreach` by itself lists every sellable category Lich currently knows about.

**noun=**_pattern_ or **n=**_pattern_
You can specify items that have a specific noun. This must be an exact match (unless using wildcards).

**name=**_pattern_ or **m=**_pattern_
You can specify items that have a specific name. The name is the short display name without the long description --
for example `uncut diamond`, `enruned mithril chest`, or `old scroll`. Matching is anchored, so the whole name must
match unless you use wildcards (`name=*diamond`).

**fullname=**_pattern_ or **f=**_pattern_
You can specify items that have a specific full name. This is like `name=pattern`, but includes things like long
descriptions. See `;foreach in inv` to get a list of item full names.

**quick=**_pattern_ or **q=**_pattern_
Identical to `fullname`, except the ends of _pattern_ are automatically wildcarded.
`;foreach q=red,blue ...` is equivalent to `;foreach f=*red*,*blue* ...`
(When used with a regular expression, `quick` behaves exactly like `fullname`.)

_pattern_ can be:
`one or more words including spaces`: Must be an exact match (subject to the anchoring rules of the chosen attribute).
`*use*asterisks*for*wildcards`: Asterisks function as wildcards. `name=*snowflake-cut*` will find anything with
'snowflake-cut' anywhere in the name, for instance.
`this,that`: Match any one of the options separated by commas.
`blue sapphire,emerald,*diamond,*emerald,uncut ruby`: You can mix the above.
`/(blue|white) crystal/`: You can match against a regular expression. The slashes are required, and matching is
always case-insensitive. (Inline regex flags after the closing slash are not supported.)

All attribute matching is case-insensitive.

You can also use **ALL**, **ANY** or **EVERYTHING** as the _what_ value to deliberately match every item. This is
required as a safety confirmation when running commands against your entire `inv` (see Targets, below).

== Targets ==

_targets_ tells ;foreach where you want to look for the items. You can specify one or more _target_, separated by commas.

Each target can be the name of an actual container in game ("cloak", "my backpack", etc.), or one of the following options:

**inv** or **inventory**
Examines the contents of all containers in your inventory. Note that containers in your hands are not in your
inventory. As a safety measure, `;foreach in inv` with commands but no _what_ filter will refuse to run unless you
explicitly say `;foreach ALL in inv; ...` (so you don't accidentally act on everything you own).

**worn**
Examines items in your inventory, *not* their contents. Want to register everything you are wearing?
`;foreach in worn; remove item; register item; wear item`

**floor** or **ground** or **room**
Examines items on the ground. *The items, not their contents.*

**loot**
Examines the contents of containers that are on the ground -- boxes, disks, errantly left-behind backpacks, etc.

**desc**
Examines items mentioned in the room description (things that are part of the room rather than loose loot).
Like `floor`/`loot`, this cannot be filtered by marked/registered status.

**locker**
Examines the contents of your locker. *If your locker is not open, ;foreach will open it and close it when it is
done.* On premium lockers it uses your `locker manifest` for a fast scan and to determine marked/registered status;
if that fails it falls back to a slower legacy scan.

**last** or **previous**
Last is the set of items that matched whatever the previous run of foreach found. You can use this to quickly undo
things, like accidentally moving all of your inventory to your locker rather than just your boxes.

When using **last**, items are reported in the container they started the previous run in -- not their current
location. So `;foreach in last; move to container` will move all (reachable) items back to their original locations.
(Filtering **last** by marked/registered status is not supported.)

**fastinv** or **qinv**
Similar to **inv**, but this uses container contents as currently known by Lich rather than doing an INV FULL. This
allows for faster startup, but with two caveats:
- Item registration/marked status is unavailable. (If you're using one of the relevant _options_, this will be
automatically converted to `inv`.)
- Containers that Lich doesn't know the contents of will be skipped. Most notably, if you have not LOOKed in a
container since you logged in, that container will be skipped. Note that `;foreach in inv` does NOT satisfy the
"looked in a container" requirement, but `;foreach in worn; look in item` probably will.

If you specified a _what_ (above section), it will further restrict the list of what foreach is working on.

**Container name suffix:** You can append a question mark to a named container so that foreach skips it gracefully
instead of failing if it is closed or missing. For example, `;foreach box in inv,disk?; move to locker` will still
work even if you have no disk.

**Collective containers:** If LOOKing at a target reports a group -- for example "You see three mannequins. Looking at
the mannequins, you see a dark grey mannequin, ..." -- foreach will operate on every container in that list. So
`;foreach on mannequins; ...` handles each mannequin in turn.

**Position keyword:** `in`, `on`, `under` and `behind` control how foreach LOOKs at named containers. Most containers
use `in`; use `on` for surfaces (tables, racks), and `under`/`behind` where appropriate.

== Commands ==

Commands are separated by semicolons (`;`), slashes (`/`) or pipes (`|`). You can only use one type of separator in a
given invocation of Foreach -- it's determined by the first one Foreach sees. The examples here all use semicolons, but
the other two formats are useful if one of your commands needs to include semicolons itself (for example, when invoking a
Lich script, or the lines of `LORESING`).

If you don't give Foreach any commands to perform, it simply spits out a list of all the matching items and some relevant
stats (including item type, which makes `;foreach in backpack` a quick way to discover what `type=` value to use). This
is useful, but usually you want to do something with items.

Any command you can send to the game can be used with Foreach. You can also invoke other Lich scripts by including the
leading `;` (for example `;foreach gem in backpack; get item; ;my_script item; put item in container`). There are also a
few shortcuts, conveniences, and some very basic scripting support (like waiting for a piece of text).

For commands to be worthwhile, there needs to be a way to refer to the current item. For this, there's some variable
replacement rules -- as noted in the next section.

== Replacements ==

Certain words within a command will be replaced with some detail about the current item. Here's a list.

**item**
The most important replacement. This is replaced with an exact reference to an item using its unique ID. It's good
for commands, but not particularly useful if you want to talk about the item in SAY or ECHO.

**container**
This is like `item`, but refers to the container the item was found in. It won't work properly if the item was not
in a container (e.g. when using the `floor`, `worn` or `desc` targets).

If you're using the `last` target, `container` refers to the container the item was *originally* in. Thus, the
following will dump your inventory into your locker and then put it all back (aside from container orders becoming
flipped):

`;foreach in inv; move to locker`
`;foreach in last; move to container`

**noun**
This will be replaced with the item noun, e.g. `diamond`, `chest`, `scroll`.

**name**
This will be replaced with the item name, e.g. `uncut diamond`, `enruned mithril chest`, `old scroll`.

== Shortcuts ==

For some normal game commands, typing `command` by itself is equivalent to `command item`. Also, if one of these
commands is the first command in the list, an implicit `get item` (or `remove item`, for worn targets) may be added
automatically when the command needs the item in hand. These commands currently are: **drop**, **place**, **sell**,
**appraise**, **register**, **mark**, **unmark**, **get**, **take**, **read**, **look**, **inspect**, **analyze**, and
**trash**.

When the *only* command is one that does not dispose of the item -- `appraise`, `register`, `mark` or `unmark` -- an
implicit `return` is also added at the end, so the item is put back where it came from. (Commands that get rid of the
item, such as `drop`, `sell`, `trash`, `place` and `giveitem`, do not get an implicit return.)

In addition, the following convenience shortcuts exist:

**move** _[what]_ **to** _where_
Shorthand for getting _what_ and then putting it in _where_. If you omit _what_, 'item' is assumed. _where_ can be a
container, or `ground`/`floor` to drop the item. If _where_ is your locker, `;foreach` tries to open it (once) and,
if successful, will close it when done.

**mv** is shorthand for **move**.

Newer versions of foreach will use `_drag` (mimicking Stormfront drag-and-drop) to reduce this from two commands to
one when they think it is safe to do so.

**fastmove** _[what]_ **to** _where_
A somewhat faster version of the above, but more prone to failing if you have oddly scripted containers involved or
tasks that involve roundtime. It utilizes typeahead -- namely sending the GET and PUT portions at the same time.

This can be shortened as **fastmv**, **fmove** or **fmv**.

Like **move**, newer versions will use `_drag` to collapse this to a single command when it is safe to do so.

**stash** _[what]_
This tries to store _what_ in your defined lootsack. If it is full, it tries lootsack2, and so on.

You can set up your lootsacks with `;vars` -- e.g.
```
;vars set lootsack=backpack
;vars set lootsack2=cloak
```

Lootsacks that stop being in your inventory while **Foreach** is running will stop having items fed to them. If every
lootsack is full, foreach pauses so you can make room (or kill it).

**giveitem** [**to**] _player_
If this is the *first* command, foreach adds an implicit `get item` before it.
Offers the item to the specified _player_ and waits for them to accept it before continuing. The player name is
autocompleted against PCs in the room: foreach errors out immediately if no matching PC, or more than one, is found.

This is only for players; NPCs don't produce the appropriate 'has accepted your offer' messaging. That said, you
don't need to wait for NPCs to accept item offers anyway -- so just use `give` instead of `giveitem` for them.

**appraise** or **appraise item**
If this is the *first* command, foreach adds an implicit `get item` before it.
If you're still holding the item at the end of running all of the commands, it will be returned to its parent
container. `appraise` by itself is shorthand for `appraise item`.

**trash** or **trash item**
Disposes of the current item using the game's TRASH verb. As the first command, an implicit `get item` is added.
`trash` by itself is shorthand for `trash item`.

**return**
Equivalent to `put item in container`. Returns whatever item Foreach is currently processing to wherever it
originally found it. Just like `put item in container`, this only works if the item is still in your hands (which you
can take advantage of in your commands). For worn targets it WEARs the item; for ground targets it PLACEs it.

== Control ==

**echo** _message_
Echoes the specified text to your client. Not sent to the game.

**pause**
Pauses ;foreach. This is particularly useful if you're using ;foreach to examine a set of items and make decisions
about them. For instance, you can write a script to test gems for orbs, pause after casting/singing, and then
manually move the gem to the correct container based on the result before unpausing foreach to continue to the next
gem.

**sleep** _time_
Pauses for _time_ seconds before continuing. Decimals are allowed, e.g. `sleep 0.5`.

**waitrt** or **waitrt?**
Waits for roundtime to finish. If you are not currently in RT, `waitrt` assumes you are about to be and waits for it
to happen. `waitrt?` only waits if you are currently in RT, and might miss RT that you're about to be in (i.e. due to
a command you sent that the server hasn't processed yet).

These function identically to, and are implemented using, the corresponding functions in Lich.

**waitcastrt** or **waitcastrt?**
As above, but waits for cast roundtime instead. The same limitations and caveats apply.

**waitfor** _text_
Waits to see the specified bit of text. Just like Lich's `waitfor`, except only one string of text can be matched.
Matching occurs in text mode (e.g. not the raw XML stream).

**waitre** _pattern_
Waits for text matching the regular expression _pattern_. Note that matching currently applies in XML mode.
You can use the `;logxml` or `;showxml` scripts to get an idea of what raw XML is being sent to the client.
[Regex101](https://regex101.com/) is a good resource for testing out patterns against text from the game before
trying them for real.

**waitmana** _amount_ or **waitmp** _amount_
Waits until you have at least this much mana.

**waithealth** _amount_ or **waithp** _amount_
Waits until you have at least this many health points.

**waitspirit** _amount_ or **waitsp** _amount_
Waits until you have at least this much spirit.

**waitstamina** _amount_ or **waitst** _amount_
Waits until you have at least this much stamina.

== Notes and gotchas ==

* `;foreach` is blind to closed containers (except lockers, which it will open automatically and close again afterwards
if it opened them). Append `?` to a named container to skip it gracefully if it is closed or missing.

* If `;foreach` is trusted (`;trust foreach`), its initial inventory-scan output is silenced so it doesn't spam your
client. Only the scan commands are squelched; the actual commands you asked for are still shown.

* Multiple instances can run at once (for example via `;force`). In Stormfront each instance gets its own status entry
in the shortcut bar where it can be paused, resumed, or stopped.

* *(Advanced / unsupported.)* A command can be prefixed with `!` to skip some of foreach's usual checks in favor of
speed. This is faster but riskier, and behavior may change between versions. Use at your own risk.

=== Technical Explanation ===

If you think `;foreach` is doing something funny, here is a rough overview of the entire logic process from start to
finish.

Depending on the level of depth you want, either just read the bold parts, just read the first sentences, or read the
whole thing.

**Option Parsing**: All of the options are interpreted, validated, and converted into a usable format.

**Implicit Commands**: The command list is fixed up.
* Shortened versions of some verbs that Foreach has special handling for are expanded to their full versions. This
includes shortened versions of `drop`, `place`, `sell`, `appraise`, `register`, `get`, `take`, `read`, `look`,
`analyze`, `inspect` and `locker`.
* If `stash` is in the command list, a list of lootsacks is built and the script exits if it can't find any.
* Any `giveitem` commands resolve to an exact player name in the room (and the script fails if no match is found).
* Commands like `place`, `sell`, `trash`, `stash`, `appraise`, `register`, `mark` and `unmark` get the word `item`
added to the end unless they already have something after them. (`sell` becomes `sell item`; `sell emerald` is
unchanged.)
* *For the first command only:* An implicit `_remget item` (for worn targets) or `get item` (everything else) is
added for commands that are known to only work with an item in hand, such as `giveitem`, `place`, `sell`, `trash`,
`appraise`, `register`, `mark` and `unmark`. (`_remget` is a hidden Foreach command equivalent to "remove the item
if its parent container is `_worn`, otherwise get it.")
* *If there is only one command:* For commands in the above list that don't dispose of an item (so not `sell`,
`trash`, `place` or `giveitem`), an implicit `return` is added to the end of the list.

**Item Scanning**: Foreach builds a list of containers and the items in them.
At this point, `foreach` has an empty map of container IDs to names (with fake IDs `_worn`, `_ground` and `_desc` for
those targets), an empty map of container IDs to lists of contents, and an empty list of containers to scan.
Throughout this process, container names are mapped as they're discovered (mainly for the item-listing mode if you
`;foreach in ...` with no commands), some container IDs are added to the "to scan" list, and each container along
with its items is added to the "to filter" list. If you're filtering by status (marked/registered, e.g.
`;foreach unmarked`), a table is made of items and their statuses.

* `inv` aborts if you specified at least one command but no item _what_, to avoid affecting everything you own
(unless you said `;foreach ALL in inv`). Otherwise it reads all of your items and their containers, saving status
data if needed.
* `last` simply restores the container/item data from the previous ;foreach invocation. It fails immediately if
you're filtering by status.
* `loot` adds each container on the ground to the "to scan" queue. It fails immediately if you're filtering by
status, as that information cannot be determined for items on the ground.
* `locker` (premium): determines your location and reads the appropriate `locker manifest`. If `;foreach` can't
determine your current location, it fails if you're filtering by status; otherwise it falls back to a legacy scan.
* `floor`/`ground`/`room` places the contents of the room (GameObj.loot) into the `_ground` container. Like `loot`,
it fails immediately if you're filtering by status.
* `desc` places room-description items into the `_desc` container. It also cannot be filtered by status.
* `worn` places `GameObj.inv` into the `_worn` container.
* Anything else is treated as a single named container: foreach LOOKs in (or on/under/behind) it to get the game to
send its contents, determines its ID, and gathers status data if needed. Collections (e.g. mannequins) expand into
one scan per member.

Then, if there are any containers to scan:
* The `sorter` script is paused, if running, to avoid spam.
* Each container is looked in (to get or refresh its inventory).
* For each container, its contents are added to the "to filter" list, and (if filtering by status and the status is
unknown) the necessary INV FULL / INV HANDS FULL commands are issued once and the data cached for reuse.
* The `sorter` script is resumed, if it was paused.

**Item Sorting**: If the SORTED, NOUNSORTED or REVERSED options are specified, they are applied to each container's
inventory.

**Item Filtering**: For each container and list of items in to_filter, items are filtered based on your criteria,
including applying options (e.g. `UNIQUE`, `MARKED`, `FIRST 5`). Containers with no items left after filtering are
dropped. If no items remain at all, ;foreach exits.

**Snapshot**: At this point, ;foreach knows every single item and container it is going to work on. This information
is saved for later use by `;foreach in last`, and then the execution phase begins.

**Execution**: For each container:
* If there are no commands, pretty-print a list of matching contents in that container.
* Otherwise, for each item, for each command:
* Replace `item`, `noun`, `name` and `container` with the item ID, item noun, item name and container ID.
* If the command starts with `$lich_char` (usually `;`), run it as a Lich script.
* If this is one of the convenience shortcuts (e.g. MOVE) or control commands (e.g. PAUSE), handle it. A couple of
noteworthy details:
* MOVE/FASTMOVE will try to learn the ID of containers it is moving things to, since `_drag` only works with IDs.
When the IDs are known it uses `_drag`, collapsing the get+put into one command.
* STASH also tries to use `_drag` when possible, which is almost always, since lootsack IDs are determined at
startup and the IDs of 'item' are always known.
* Some commands define a "run this before the next command" procedure (usually `waitrt?` and sometimes waiting for
a prompt). Most commands clear this, but some control commands (`waitfor`, `waitre`, `pause`, `sleep`) leave it
for the next command to resolve. This prevents issues like trying to `waitfor` a message that would scroll by
while in roundtime, or the script waiting to pause and thus not being unpausable until you are out of roundtime.







{{Third-Party Software}}
{{Third-Party Software}}
[[Category:Third-Party Software]]
{{top}}
{{top}}

Latest revision as of 10:54, 24 June 2026

Lich:Script foreach is a third party script and is not maintained by Simutronics. Simutronics is not responsible for the accuracy of the information presented on this page, nor is it liable for issues stemming from the use of the application on players' personal devices.

What is it?

foreach is a script for sending a series of commands for each item that matches its criteria.

While not a full replacement for "proper" purpose-built Lich scripts, it is still frequently useful in its own regard. Anywhere you would otherwise repeat the same handful of commands once per item -- moving boxes, cutting gems, reading scrolls, selling for a bounty -- foreach can do it in a single line.

I don't want to read docs, can you give me some examples?

No rogues around?  Move all your boxes to your locker:
 `;foreach box in inv; move to locker`
Move all your boxes back out of your locker:
 `;foreach box in locker; move to backpack`
Own a gemcutter and want to cut all the gems in a container?
 `;foreach gem in red sack; move to gemcutter; turn gemcutter; waitrt; move to blue sack`
Getting boxes picked?
 `;foreach box in inv; get item; give item to Rogue; waitfor Rogue offers you; accept item`
 *(This'll only work if you're fast enough to empty boxes while the rogue is picking)*
Checking for orb gems?
 Sorcerer: `;foreach gem in queue bag; get item; waitmana 4; prep 704; cast item; pause; put item in reject bag`
 Bard using `;loresing`: `;foreach gem in queue bag; get item; waitfor You remove; waitmana 20; ;loresing purpose noun; pause; waitrt?; put item in reject bag`
 While the script is paused, put the gem in the orb bag if it's an orb.  `;unpause` will put it in the reject bag if you're still holding it.
Bulk reading scrolls?
 `;foreach scroll in inv; read item`
Appraise every gem in a container (foreach gets each one, appraises it, and puts it back):
 `;foreach gem in backpack; appraise`
Accidentally move a bunch of items to the wrong container using foreach?
 `;foreach in last; move to container` *(back where they started)*
 *or* `;foreach in last; get item; move to correct backpack`
Turning in gems or herbs for a bounty?
 `;foreach name=uncut diamond in inv; get item; sell item`
Don't want to sell ALL of your diamonds for said bounty?
 `;foreach first 7 name=uncut diamond in inv; get item; sell item`
Sell everything in a container that the local pawnshop will buy:
 `;foreach sellable=pawnshop in my cloak; get item; sell item`
Doing a long task and want to be able to resume it later (possibly on the same source container)?
 `;foreach unmarked gem in wherever; get item; do lots of things; mark item; return` as many times as needed, followed by
 `;foreach marked gem in wherever; get item; unmark item`
 (`wherever` must be a container in your inventory or your entire `inv`)
Need to ditch your sorcerer wands but want to keep the wizard ones?
 `;foreach q=/(bloodwood|twisted|yew|bone|glass|thanot) wand/ in inv; sell`
 (This uses regular-expression pattern matching -- note the slashes.)
Match a specific full name (article and adjectives included):
 `;foreach name=*quartz orb in inv; get item; put item in locker`


That's nice. But what can it REALLY do?

Usage

 ;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**;** _command1_**;** _command2_**;** ...]
 ;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**/** _command1_**/** _command2_**/** ...]
 ;foreach** _[options]_ _[what]_ **in/on/under/behind** _targets_ [**|** _command1_**|** _command2_**|** ...]

Typing `;foreach` or `;foreach help` by itself prints the built-in help, including the live list of item types and sellable categories that Lich currently knows about.

Options

_options_ is a set of optional filters on what matching items `foreach` will operate on. It can consist of zero or more of the following:

**registered** _or_ **unregistered**
 Only matches items that are registered or not registered.  This option is only available if the items in question
 are in your inventory or your premium locker.  (`locker manifest` is used to determine item status in the latter case,
 which is not available for standard lockers.)
**marked** _or_ **unmarked**
 Only matches items that are marked or not marked as unsellable.  This has the same restrictions as the above.
 You can use this in conjunction with MARKing items as part of your ;foreach script to prevent operating on the same
 item more than once in situations where you might run ;foreach multiple times.
**unique**
 Only the first item with any given full name will be matched.  This is global across all containers, so if you have
 the same item in two different containers only the first item (whichever `foreach` sees first) will be matched.
**first _N_**
 Stop after _N_ matching items have been encountered.  (The word `first` is optional, so `;foreach 5 gem ...` works.)
**skip _N_** _or_ **after _N_**
 Skip the first _N_ matching items.
**sort** _or_ **sorted**
 Sort items by full name within each respective container.  Articles "a", "an", "some" and "the" are ignored when
 sorting.  Containers are still handled one at a time, and the order of the containers themselves is not affected.
**nounsort** _or_ **nsort** _(also_ **nsorted** _/_ **nounsorted**_)_
 Sort items by noun first, then by full name, within each respective container.  Useful when you want all of one kind
 of item grouped together regardless of adjectives.  As with **sort**, articles are ignored and container order is
 unaffected.  (**sort** and **nounsort** are mutually exclusive -- specify at most one.)
**reverse** _or_ **reversed**
 Reverse the order of items within each container.  If used alone, this means the last item in each container is
 processed first and vice versa.  If used with **sorted** (or **nounsort**), items are handled in descending order
 rather than ascending.  Containers are still handled one at a time, and the order of the containers themselves is not
 affected.

Options are applied roughly in the order listed above. You can combine **first** with **skip**: `;foreach first 5 after 10` will match items 11 through 15.

What

_what_ allows you to filter the types of items `foreach` acts on. It can be one of the following:

**type=**_pattern_   or   **t=**_pattern_   or   simply _pattern_
  You can specify any type of item that Lich knows about.  Examples include 'gem', 'wand' and 'scroll'
  (which includes things like palimpsests and other 'alternate names' for scrolls).  `;foreach` by itself will show
  all the known types.  `;foreach in inv` with no commands will show the types of all items it finds.
  You can use `type=none` (or `type=unknown`) to explicitly find items that have no defined type according to Lich.
  **Note:** This is only as accurate as Lich's own type data.  You may be able to get more accurate type data by
  downloading and running the `gameobjadd` script at startup, or by keeping `gameobj-data.xml` up to date.
**sellable=**_pattern_   or   **s=**_pattern_
  You can match items by which shops will buy them, based on Lich's sellable data.  For example,
  `;foreach sellable=pawnshop in my cloak; get item; sell item` will sell everything the pawnshop accepts.
  Use `sellable=none` (or `sellable=unknown`) to match items with no known sellable category.
  `;foreach` by itself lists every sellable category Lich currently knows about.
**noun=**_pattern_   or   **n=**_pattern_
  You can specify items that have a specific noun.  This must be an exact match (unless using wildcards).
**name=**_pattern_   or   **m=**_pattern_
  You can specify items that have a specific name.  The name is the short display name without the long description --
  for example `uncut diamond`, `enruned mithril chest`, or `old scroll`.  Matching is anchored, so the whole name must
  match unless you use wildcards (`name=*diamond`).
**fullname=**_pattern_   or   **f=**_pattern_
  You can specify items that have a specific full name.  This is like `name=pattern`, but includes things like long
  descriptions.  See `;foreach in inv` to get a list of item full names.
**quick=**_pattern_   or   **q=**_pattern_
  Identical to `fullname`, except the ends of _pattern_ are automatically wildcarded.
  `;foreach q=red,blue ...` is equivalent to `;foreach f=*red*,*blue* ...`
  (When used with a regular expression, `quick` behaves exactly like `fullname`.)

_pattern_ can be:

  `one or more words including spaces`: Must be an exact match (subject to the anchoring rules of the chosen attribute).
  `*use*asterisks*for*wildcards`: Asterisks function as wildcards.  `name=*snowflake-cut*` will find anything with
   'snowflake-cut' anywhere in the name, for instance.
  `this,that`: Match any one of the options separated by commas.
  `blue sapphire,emerald,*diamond,*emerald,uncut ruby`: You can mix the above.
  `/(blue|white) crystal/`: You can match against a regular expression.  The slashes are required, and matching is
   always case-insensitive.  (Inline regex flags after the closing slash are not supported.)

All attribute matching is case-insensitive.

You can also use **ALL**, **ANY** or **EVERYTHING** as the _what_ value to deliberately match every item. This is required as a safety confirmation when running commands against your entire `inv` (see Targets, below).

Targets

_targets_ tells ;foreach where you want to look for the items. You can specify one or more _target_, separated by commas.

Each target can be the name of an actual container in game ("cloak", "my backpack", etc.), or one of the following options:

**inv** or **inventory**
 Examines the contents of all containers in your inventory.  Note that containers in your hands are not in your
 inventory.  As a safety measure, `;foreach in inv` with commands but no _what_ filter will refuse to run unless you
 explicitly say `;foreach ALL in inv; ...` (so you don't accidentally act on everything you own).
**worn**
 Examines items in your inventory, *not* their contents.  Want to register everything you are wearing?
 `;foreach in worn; remove item; register item; wear item`
**floor** or **ground** or **room**
 Examines items on the ground.  *The items, not their contents.*
**loot**
 Examines the contents of containers that are on the ground -- boxes, disks, errantly left-behind backpacks, etc.
**desc**
 Examines items mentioned in the room description (things that are part of the room rather than loose loot).
 Like `floor`/`loot`, this cannot be filtered by marked/registered status.
**locker**
 Examines the contents of your locker.  *If your locker is not open, ;foreach will open it and close it when it is
 done.*  On premium lockers it uses your `locker manifest` for a fast scan and to determine marked/registered status;
 if that fails it falls back to a slower legacy scan.
**last** or **previous**
 Last is the set of items that matched whatever the previous run of foreach found.  You can use this to quickly undo
 things, like accidentally moving all of your inventory to your locker rather than just your boxes.
 When using **last**, items are reported in the container they started the previous run in -- not their current
 location.  So `;foreach in last; move to container` will move all (reachable) items back to their original locations.
 (Filtering **last** by marked/registered status is not supported.)
**fastinv** or **qinv**
 Similar to **inv**, but this uses container contents as currently known by Lich rather than doing an INV FULL.  This
 allows for faster startup, but with two caveats:
 - Item registration/marked status is unavailable.  (If you're using one of the relevant _options_, this will be
   automatically converted to `inv`.)
 - Containers that Lich doesn't know the contents of will be skipped.  Most notably, if you have not LOOKed in a
   container since you logged in, that container will be skipped.  Note that `;foreach in inv` does NOT satisfy the
   "looked in a container" requirement, but `;foreach in worn; look in item` probably will.
 If you specified a _what_ (above section), it will further restrict the list of what foreach is working on.
    • Container name suffix:** You can append a question mark to a named container so that foreach skips it gracefully

instead of failing if it is closed or missing. For example, `;foreach box in inv,disk?; move to locker` will still work even if you have no disk.

    • Collective containers:** If LOOKing at a target reports a group -- for example "You see three mannequins. Looking at

the mannequins, you see a dark grey mannequin, ..." -- foreach will operate on every container in that list. So `;foreach on mannequins; ...` handles each mannequin in turn.

    • Position keyword:** `in`, `on`, `under` and `behind` control how foreach LOOKs at named containers. Most containers

use `in`; use `on` for surfaces (tables, racks), and `under`/`behind` where appropriate.

Commands

Commands are separated by semicolons (`;`), slashes (`/`) or pipes (`|`). You can only use one type of separator in a given invocation of Foreach -- it's determined by the first one Foreach sees. The examples here all use semicolons, but the other two formats are useful if one of your commands needs to include semicolons itself (for example, when invoking a Lich script, or the lines of `LORESING`).

If you don't give Foreach any commands to perform, it simply spits out a list of all the matching items and some relevant stats (including item type, which makes `;foreach in backpack` a quick way to discover what `type=` value to use). This is useful, but usually you want to do something with items.

Any command you can send to the game can be used with Foreach. You can also invoke other Lich scripts by including the leading `;` (for example `;foreach gem in backpack; get item; ;my_script item; put item in container`). There are also a few shortcuts, conveniences, and some very basic scripting support (like waiting for a piece of text).

For commands to be worthwhile, there needs to be a way to refer to the current item. For this, there's some variable replacement rules -- as noted in the next section.

Replacements

Certain words within a command will be replaced with some detail about the current item. Here's a list.

**item**
 The most important replacement.  This is replaced with an exact reference to an item using its unique ID.  It's good
 for commands, but not particularly useful if you want to talk about the item in SAY or ECHO.
**container**
 This is like `item`, but refers to the container the item was found in.  It won't work properly if the item was not
 in a container (e.g. when using the `floor`, `worn` or `desc` targets).
 If you're using the `last` target, `container` refers to the container the item was *originally* in.  Thus, the
 following will dump your inventory into your locker and then put it all back (aside from container orders becoming
 flipped):
 `;foreach in inv; move to locker`
 `;foreach in last; move to container`
**noun**
 This will be replaced with the item noun, e.g. `diamond`, `chest`, `scroll`.
**name**
 This will be replaced with the item name, e.g. `uncut diamond`, `enruned mithril chest`, `old scroll`.

Shortcuts

For some normal game commands, typing `command` by itself is equivalent to `command item`. Also, if one of these commands is the first command in the list, an implicit `get item` (or `remove item`, for worn targets) may be added automatically when the command needs the item in hand. These commands currently are: **drop**, **place**, **sell**,

    • appraise**, **register**, **mark**, **unmark**, **get**, **take**, **read**, **look**, **inspect**, **analyze**, and
    • trash**.

When the *only* command is one that does not dispose of the item -- `appraise`, `register`, `mark` or `unmark` -- an implicit `return` is also added at the end, so the item is put back where it came from. (Commands that get rid of the item, such as `drop`, `sell`, `trash`, `place` and `giveitem`, do not get an implicit return.)

In addition, the following convenience shortcuts exist:

**move** _[what]_ **to** _where_
 Shorthand for getting _what_ and then putting it in _where_.  If you omit _what_, 'item' is assumed.  _where_ can be a
 container, or `ground`/`floor` to drop the item.  If _where_ is your locker, `;foreach` tries to open it (once) and,
 if successful, will close it when done.
 **mv** is shorthand for **move**.
 Newer versions of foreach will use `_drag` (mimicking Stormfront drag-and-drop) to reduce this from two commands to
 one when they think it is safe to do so.
**fastmove** _[what]_ **to** _where_
 A somewhat faster version of the above, but more prone to failing if you have oddly scripted containers involved or
 tasks that involve roundtime.  It utilizes typeahead -- namely sending the GET and PUT portions at the same time.
 This can be shortened as **fastmv**, **fmove** or **fmv**.
 Like **move**, newer versions will use `_drag` to collapse this to a single command when it is safe to do so.
**stash** _[what]_
 This tries to store _what_ in your defined lootsack.  If it is full, it tries lootsack2, and so on.
 You can set up your lootsacks with `;vars` -- e.g.
 ```
 ;vars set lootsack=backpack
 ;vars set lootsack2=cloak
 ```
 Lootsacks that stop being in your inventory while **Foreach** is running will stop having items fed to them.  If every
 lootsack is full, foreach pauses so you can make room (or kill it).
**giveitem** [**to**] _player_
 If this is the *first* command, foreach adds an implicit `get item` before it.
 Offers the item to the specified _player_ and waits for them to accept it before continuing.  The player name is
 autocompleted against PCs in the room: foreach errors out immediately if no matching PC, or more than one, is found.
 This is only for players; NPCs don't produce the appropriate 'has accepted your offer' messaging.  That said, you
 don't need to wait for NPCs to accept item offers anyway -- so just use `give` instead of `giveitem` for them.
**appraise** or **appraise item**
 If this is the *first* command, foreach adds an implicit `get item` before it.
 If you're still holding the item at the end of running all of the commands, it will be returned to its parent
 container.  `appraise` by itself is shorthand for `appraise item`.
**trash** or **trash item**
 Disposes of the current item using the game's TRASH verb.  As the first command, an implicit `get item` is added.
 `trash` by itself is shorthand for `trash item`.
**return**
 Equivalent to `put item in container`.  Returns whatever item Foreach is currently processing to wherever it
 originally found it.  Just like `put item in container`, this only works if the item is still in your hands (which you
 can take advantage of in your commands).  For worn targets it WEARs the item; for ground targets it PLACEs it.

Control

**echo** _message_
 Echoes the specified text to your client.  Not sent to the game.
**pause**
 Pauses ;foreach.  This is particularly useful if you're using ;foreach to examine a set of items and make decisions
 about them.  For instance, you can write a script to test gems for orbs, pause after casting/singing, and then
 manually move the gem to the correct container based on the result before unpausing foreach to continue to the next
 gem.
**sleep** _time_
 Pauses for _time_ seconds before continuing.  Decimals are allowed, e.g. `sleep 0.5`.
**waitrt** or **waitrt?**
 Waits for roundtime to finish.  If you are not currently in RT, `waitrt` assumes you are about to be and waits for it
 to happen.  `waitrt?` only waits if you are currently in RT, and might miss RT that you're about to be in (i.e. due to
 a command you sent that the server hasn't processed yet).
 These function identically to, and are implemented using, the corresponding functions in Lich.
**waitcastrt** or **waitcastrt?**
 As above, but waits for cast roundtime instead.  The same limitations and caveats apply.
**waitfor** _text_
 Waits to see the specified bit of text.  Just like Lich's `waitfor`, except only one string of text can be matched.
 Matching occurs in text mode (e.g. not the raw XML stream).
**waitre** _pattern_
 Waits for text matching the regular expression _pattern_.  Note that matching currently applies in XML mode.
 You can use the `;logxml` or `;showxml` scripts to get an idea of what raw XML is being sent to the client.
 [Regex101](https://regex101.com/) is a good resource for testing out patterns against text from the game before
 trying them for real.
**waitmana** _amount_ or **waitmp** _amount_
 Waits until you have at least this much mana.
**waithealth** _amount_ or **waithp** _amount_
 Waits until you have at least this many health points.
**waitspirit** _amount_ or **waitsp** _amount_
 Waits until you have at least this much spirit.
**waitstamina** _amount_ or **waitst** _amount_
 Waits until you have at least this much stamina.

Notes and gotchas

* `;foreach` is blind to closed containers (except lockers, which it will open automatically and close again afterwards
  if it opened them).  Append `?` to a named container to skip it gracefully if it is closed or missing.
* If `;foreach` is trusted (`;trust foreach`), its initial inventory-scan output is silenced so it doesn't spam your
  client.  Only the scan commands are squelched; the actual commands you asked for are still shown.
* Multiple instances can run at once (for example via `;force`).  In Stormfront each instance gets its own status entry
  in the shortcut bar where it can be paused, resumed, or stopped.
* *(Advanced / unsupported.)*  A command can be prefixed with `!` to skip some of foreach's usual checks in favor of
  speed.  This is faster but riskier, and behavior may change between versions.  Use at your own risk.

Technical Explanation

If you think `;foreach` is doing something funny, here is a rough overview of the entire logic process from start to finish.

Depending on the level of depth you want, either just read the bold parts, just read the first sentences, or read the whole thing.

**Option Parsing**: All of the options are interpreted, validated, and converted into a usable format.
**Implicit Commands**: The command list is fixed up.
  * Shortened versions of some verbs that Foreach has special handling for are expanded to their full versions.  This
    includes shortened versions of `drop`, `place`, `sell`, `appraise`, `register`, `get`, `take`, `read`, `look`,
    `analyze`, `inspect` and `locker`.
  * If `stash` is in the command list, a list of lootsacks is built and the script exits if it can't find any.
  * Any `giveitem` commands resolve to an exact player name in the room (and the script fails if no match is found).
  * Commands like `place`, `sell`, `trash`, `stash`, `appraise`, `register`, `mark` and `unmark` get the word `item`
    added to the end unless they already have something after them.  (`sell` becomes `sell item`; `sell emerald` is
    unchanged.)
  * *For the first command only:* An implicit `_remget item` (for worn targets) or `get item` (everything else) is
    added for commands that are known to only work with an item in hand, such as `giveitem`, `place`, `sell`, `trash`,
    `appraise`, `register`, `mark` and `unmark`.  (`_remget` is a hidden Foreach command equivalent to "remove the item
    if its parent container is `_worn`, otherwise get it.")
  * *If there is only one command:* For commands in the above list that don't dispose of an item (so not `sell`,
    `trash`, `place` or `giveitem`), an implicit `return` is added to the end of the list.
**Item Scanning**: Foreach builds a list of containers and the items in them.
  At this point, `foreach` has an empty map of container IDs to names (with fake IDs `_worn`, `_ground` and `_desc` for
  those targets), an empty map of container IDs to lists of contents, and an empty list of containers to scan.
  Throughout this process, container names are mapped as they're discovered (mainly for the item-listing mode if you
  `;foreach in ...` with no commands), some container IDs are added to the "to scan" list, and each container along
  with its items is added to the "to filter" list.  If you're filtering by status (marked/registered, e.g.
  `;foreach unmarked`), a table is made of items and their statuses.
  * `inv` aborts if you specified at least one command but no item _what_, to avoid affecting everything you own
    (unless you said `;foreach ALL in inv`).  Otherwise it reads all of your items and their containers, saving status
    data if needed.
  * `last` simply restores the container/item data from the previous ;foreach invocation.  It fails immediately if
    you're filtering by status.
  * `loot` adds each container on the ground to the "to scan" queue.  It fails immediately if you're filtering by
    status, as that information cannot be determined for items on the ground.
  * `locker` (premium): determines your location and reads the appropriate `locker manifest`.  If `;foreach` can't
    determine your current location, it fails if you're filtering by status; otherwise it falls back to a legacy scan.
  * `floor`/`ground`/`room` places the contents of the room (GameObj.loot) into the `_ground` container.  Like `loot`,
    it fails immediately if you're filtering by status.
  * `desc` places room-description items into the `_desc` container.  It also cannot be filtered by status.
  * `worn` places `GameObj.inv` into the `_worn` container.
  * Anything else is treated as a single named container: foreach LOOKs in (or on/under/behind) it to get the game to
    send its contents, determines its ID, and gathers status data if needed.  Collections (e.g. mannequins) expand into
    one scan per member.
  Then, if there are any containers to scan:
  * The `sorter` script is paused, if running, to avoid spam.
  * Each container is looked in (to get or refresh its inventory).
  * For each container, its contents are added to the "to filter" list, and (if filtering by status and the status is
    unknown) the necessary INV FULL / INV HANDS FULL commands are issued once and the data cached for reuse.
  * The `sorter` script is resumed, if it was paused.
**Item Sorting**: If the SORTED, NOUNSORTED or REVERSED options are specified, they are applied to each container's
  inventory.
**Item Filtering**: For each container and list of items in to_filter, items are filtered based on your criteria,
  including applying options (e.g. `UNIQUE`, `MARKED`, `FIRST 5`).  Containers with no items left after filtering are
  dropped.  If no items remain at all, ;foreach exits.
**Snapshot**: At this point, ;foreach knows every single item and container it is going to work on.  This information
  is saved for later use by `;foreach in last`, and then the execution phase begins.
**Execution**: For each container:
  * If there are no commands, pretty-print a list of matching contents in that container.
  * Otherwise, for each item, for each command:
    * Replace `item`, `noun`, `name` and `container` with the item ID, item noun, item name and container ID.
    * If the command starts with `$lich_char` (usually `;`), run it as a Lich script.
    * If this is one of the convenience shortcuts (e.g. MOVE) or control commands (e.g. PAUSE), handle it.  A couple of
      noteworthy details:
      * MOVE/FASTMOVE will try to learn the ID of containers it is moving things to, since `_drag` only works with IDs.
        When the IDs are known it uses `_drag`, collapsing the get+put into one command.
      * STASH also tries to use `_drag` when possible, which is almost always, since lootsack IDs are determined at
        startup and the IDs of 'item' are always known.
    * Some commands define a "run this before the next command" procedure (usually `waitrt?` and sometimes waiting for
      a prompt).  Most commands clear this, but some control commands (`waitfor`, `waitre`, `pause`, `sleep`) leave it
      for the next command to resolve.  This prevents issues like trying to `waitfor` a message that would scroll by
      while in roundtime, or the script waiting to pause and thus not being unpausable until you are out of roundtime.



Third-Party Software - edit
Lich Installation: Lich
Downloadable Lich Scripts: Go2 | Map | Repository | Popular Scripts
Return to the top of this page.