Heavy FS AO system modifications

NEEDS TESTING. Despite my best efforts and deeming this beta-ready it may still contain some bugs.

- Independent tracks per animation state - multiple of these can be played at the same time
- Animation groups - again, at the same time, but only as grouped with selected animations
- "Always played" quasi-state that can be used for bento ears, tails etc.
- Context menus on the animations list
- Tried to keep it backwards compatible

Credits given where credits are due:
Poked Zi Ree few times for opinions, suggestions and ideas - thanks!

Signed-off-by: PanteraPolnocy <panterapolnocy@gmail.com>
This commit is contained in:
PanteraPolnocy
2026-06-11 18:43:42 +02:00
parent a3a1c71499
commit 48c057cfe6
12 changed files with 2989 additions and 451 deletions
+943 -108
View File
File diff suppressed because it is too large Load Diff
+54 -3
View File
@@ -32,9 +32,13 @@
#include "lltransientdockablefloater.h"
#include "aoset.h"
#include <map>
#include <set>
class LLButton;
class LLComboBox;
class LLCheckBoxCtrl;
class LLContextMenu;
class LLMenuButton;
class LLMenuItemCallGL;
class LLScrollListCtrl;
@@ -50,14 +54,14 @@ class FloaterAO
private:
FloaterAO(const LLSD& key);
~FloaterAO() = default;
~FloaterAO();
public:
bool postBuild() override;
void onOpen(const LLSD& key) override;
void onClose(bool app_quitting) override;
void draw() override;
void updateList();
void updateScrollListData();
void updateSetParameters();
void updateAnimationList();
@@ -65,7 +69,25 @@ class FloaterAO
EAcceptance* accept, std::string& tooltip_msg) override;
protected:
LLScrollListItem* addAnimation(const std::string& name);
struct RowInfo
{
std::string mKind; // "single", "group", "member", "trackmember"
S32 mIndex{ -1 };
S32 mMember{ -1 }; // member index within a group or track, -1 for the row itself
};
LLScrollListItem* addRow(LLScrollListCtrl* list, const std::string& icon, const std::string& name, const RowInfo& info, const std::string& tooltip, bool indented, bool bold);
bool getRowInfo(LLScrollListItem* item, RowInfo& info) const;
static LLSD encodeRowValue(const RowInfo& info);
void rebuildAnimationList();
void rebuildTrackSelector();
std::string expansionKey() const;
bool isFolderExpanded(const LLUUID& folderID) const;
void setFolderExpanded(const LLUUID& folderID, bool expanded);
void requestListRebuild();
void onSelectSet();
void onSelectSetSmall();
@@ -96,6 +118,20 @@ class FloaterAO
void onClickLess();
void onDoubleClick();
void onClickRename();
bool renameGroupCallback(const LLSD& notification, const LLSD& response, S32 stepIndex);
void onAnimationListRightClick(LLUICtrl* ctrl, S32 x, S32 y, MASK mask);
void showContextMenu(LLScrollListCtrl* list, S32 x, S32 y);
void onToggleRowExpand(const RowInfo& info);
void onExtractMember(const RowInfo& info);
void onDeleteRow(const RowInfo& info);
void onRenameRow(const RowInfo& info);
void onSelectTrackTab();
void onClickAddTrack();
void updateCycleControlValues();
void onAnimationChanged(const LLUUID& animation);
void reloading(bool reload);
@@ -136,12 +172,18 @@ class FloaterAO
LLScrollListItem* mCurrentBoldItem;
LLButton* mMoveUpButton;
LLButton* mMoveDownButton;
LLButton* mRenameButton;
LLButton* mTrashButton;
LLCheckBoxCtrl* mCycleCheckBox;
LLCheckBoxCtrl* mRandomizeCheckBox;
LLTextBox* mCycleTimeTextLabel;
LLSpinCtrl* mCycleTimeSpinner;
LLComboBox* mTrackSelector;
LLButton* mTrackAddButton;
LLPanel* mDropZonePanel;
bool mDropZoneHovered;
LLButton* mReloadButton;
LLButton* mPreviousButton;
@@ -161,6 +203,15 @@ class FloaterAO
bool mCanDragAndDrop;
bool mImportRunning;
bool mMore;
bool mRebuildPending;
S32 mCurrentTrack; // 0 = main state list, N = mTracks[N-1]
std::string mLastSelectedStateName; // "set|state" key, resets track tab on real switches
std::string mPendingTrackSelection; // track to select after the next reload
std::string mLastSelectedRowValue; // detects selection transitions for auto-expand
std::map<std::string, std::set<LLUUID>> mExpandedFolders;
LLHandle<LLContextMenu> mContextMenuHandle;
};
#endif // AO_H
+1547 -276
View File
File diff suppressed because it is too large Load Diff
+84 -6
View File
@@ -33,6 +33,11 @@
#include "llsingleton.h"
#include "llviewerinventory.h"
#include <map>
#include <memory>
class LLInventoryCategory;
class AOTimerCollection : public LLEventTimer
{
public:
@@ -74,6 +79,23 @@ protected:
// ----------------------------------------------------
// timer cycles the state's step list instead of one of its tracks - used for the continuously playing "Always" state
constexpr S32 AO_TRACK_INDEX_STEPS = -1;
class AOTrackTimer : public LLEventTimer
{
public:
AOTrackTimer(S32 stateEnum, S32 trackIndex, F32 period);
~AOTrackTimer() = default;
bool tick() override;
protected:
S32 mStateEnum;
S32 mTrackIndex;
};
class AOEngine : public LLSingleton<AOEngine>
{
LLSINGLETON(AOEngine);
@@ -93,7 +115,7 @@ public:
void tick();
void update();
void reload(bool fromTimer);
void reloadStateAnimations(AOSet* set, AOSet::AOState* state);
bool reloadStateAnimations(AOSet* set, AOSet::AOState* state);
void clear(bool fromTimer);
const LLUUID& getAOFolder() const;
@@ -103,20 +125,40 @@ public:
bool removeSet(AOSet* set);
void addAnimation(const AOSet* set, AOSet::AOState* state, const LLInventoryItem* item, bool reload = true);
bool removeAnimation(const AOSet* set, AOSet::AOState* state, S32 index);
bool removeAnimation(const AOSet* set, AOSet::AOState* state, S32 stepIndex, S32 memberIndex = -1);
void checkSitCancel();
void checkBelowWater(bool check_underwater);
bool importNotecard(const LLInventoryItem* item);
void processImport(bool from_timer);
bool swapWithPrevious(AOSet::AOState* state, S32 index);
bool swapWithNext(AOSet::AOState* state, S32 index);
bool swapWithPrevious(AOSet::AOState* state, S32 stepIndex, S32 memberIndex = -1);
bool swapWithNext(AOSet::AOState* state, S32 stepIndex, S32 memberIndex = -1);
void cycleTimeout(const AOSet* set);
void cycle(eCycleMode cycleMode, bool resetTimer = false);
void playAnimation(const LLUUID& animation);
void addAnimationToGroup(AOSet::AOState* state, S32 stepIndex, const LLInventoryItem* item);
void createGroupFromMerge(AOSet::AOState* state, S32 stepIndex, const LLInventoryItem* item);
bool createGroupFromFolder(AOSet::AOState* state, const LLInventoryCategory* category);
void extractMemberFromGroup(AOSet::AOState* state, S32 stepIndex, S32 memberIndex);
bool renameGroup(AOSet::AOState* state, S32 stepIndex, std::string_view newName);
std::string createEmptyTrack(AOSet::AOState* state);
void addAnimationToTrack(AOSet::AOState* state, S32 trackIndex, const LLInventoryItem* item);
void removeTrack(AOSet::AOState* state, S32 trackIndex);
void removeTrackAnimation(AOSet::AOState* state, S32 trackIndex, S32 memberIndex);
bool swapTrackAnimationWithPrevious(AOSet::AOState* state, S32 trackIndex, S32 memberIndex);
bool swapTrackAnimationWithNext(AOSet::AOState* state, S32 trackIndex, S32 memberIndex);
void setTrackCycle(AOSet::AOState* state, S32 trackIndex, bool cycle);
void setTrackRandomize(AOSet::AOState* state, S32 trackIndex, bool randomize);
void setTrackCycleTime(AOSet::AOState* state, S32 trackIndex, F32 time);
void playTrackAnimation(AOSet::AOState* state, S32 trackIndex, S32 memberIndex);
void trackTimeout(S32 stateEnum, S32 trackIndex);
void playAlwaysAnimation(S32 stepIndex, S32 memberIndex = -1);
void playAnimation(S32 stepIndex, S32 memberIndex = -1);
const AOSet* getCurrentSet() const;
const AOSet::AOState* getCurrentState() const;
@@ -176,7 +218,28 @@ protected:
std::string getSetFolderName(const AOSet* set) const;
std::string getStateFolderName(const AOSet::AOState* state) const;
bool createAnimationLink(AOSet::AOState* state, const LLInventoryItem* item);
void stopCurrentAnimations(AOSet::AOState* state, bool skipFirst = false);
bool swapStateAnimations(AOSet::AOState* state, const uuid_vec_t& animations);
void startStateTracks(AOSet::AOState* state);
void stopActiveTracks();
void startAlwaysAnimations();
void stopAlwaysAnimations();
void refreshAlwaysTimers();
void cycleAlwaysStep();
void setItemDescription(const LLUUID& itemID, const std::string& description);
void updateMemberSortOrder(std::vector<AOSet::AOAnimation>& animations);
void collapseGroupToSingle(AOSet::AOState* state, AOSet::AOAnimationStep& step);
void saveGroup(const AOSet::AOAnimationStep& step);
void saveTrack(const AOSet::AOTrack& track);
std::string getGroupFolderName(const AOSet::AOAnimationStep& step) const;
std::string getTrackFolderName(const AOSet::AOTrack& track) const;
std::string sanitiseFolderName(const std::string& name, const std::string& fallback) const;
std::string nextGroupName(const AOSet::AOState* state) const;
std::string nextTrackName(const AOSet::AOState* state) const;
bool readAnimationLinks(const LLUUID& categoryID, std::vector<AOSet::AOAnimation>& animations);
void processImportState(AOSet::AOState* state);
bool createAnimationLink(const LLUUID& categoryID, const LLInventoryItem* item);
bool findForeignItems(const LLUUID& uuid) const;
void purgeFolder(const LLUUID& uuid) const;
@@ -220,6 +283,21 @@ protected:
std::vector<AOSet*> mOldImportSets;
S32 mImportRetryCount;
// timers of the active state's cycling tracks, and the state
// whose tracks are currently playing. The pointer stays valid because tracks get
// stopped in clear() before any AOSet object goes away
std::vector<std::unique_ptr<AOTrackTimer>> mActiveTrackTimers;
AOSet::AOState* mActiveTrackState{ nullptr };
// the "Always" pseudo state of the current set while it is playing, with its
// own step cycle timer and track timers that survive motion changes
std::vector<std::unique_ptr<AOTrackTimer>> mAlwaysTimers;
AOSet::AOState* mActiveAlwaysState{ nullptr };
// pending additions while a group subfolder is created asynchronously, keyed by
// the merge target's link UUID - prevents duplicate folders on fast multi-drop
std::map<LLUUID, std::vector<const LLInventoryItem*>> mPendingGroupMerges;
boost::signals2::connection mRegionChangeConnection;
};
+98 -43
View File
@@ -70,7 +70,8 @@ AOSet::AOSet(const LLUUID& inventoryID)
"Floating|Swim.H",
"Swimming Forward|Swim.N",
"Swimming Up|Swim.U",
"Swimming Down|Swim.D"
"Swimming Down|Swim.D",
"Always"
};
// keep number and order in sync with the enum in the declaration
@@ -100,7 +101,8 @@ AOSet::AOSet(const LLUUID& inventoryID)
ANIM_AGENT_HOVER, // needs special treatment
ANIM_AGENT_FLY, // needs special treatment
ANIM_AGENT_HOVER_UP, // needs special treatment
ANIM_AGENT_HOVER_DOWN // needs special treatment
ANIM_AGENT_HOVER_DOWN, // needs special treatment
LLUUID::null // "Always" has no motion to override
};
for (S32 index = 0; index < AOSTATES_MAX; ++index)
@@ -110,10 +112,11 @@ AOSet::AOSet(const LLUUID& inventoryID)
mStates[index].mName = stateNameList[0]; // for quick reference
mStates[index].mAlternateNames = stateNameList; // to get all possible names, including mName
mStates[index].mNum = index;
mStates[index].mRemapID = stateUUIDs[index];
mStates[index].mInventoryUUID = LLUUID::null;
mStates[index].mCurrentAnimation = 0;
mStates[index].mCurrentAnimationID = LLUUID::null;
mStates[index].mCurrentAnimationIDs.clear();
mStates[index].mCycle = false;
mStates[index].mRandom = false;
mStates[index].mCycleTime = 0;
@@ -151,6 +154,12 @@ AOSet::AOState* AOSet::getStateByName(const std::string& name)
AOSet::AOState* AOSet::getStateByRemapID(const LLUUID& id)
{
// "Always" state has a null remap id and must never be picked up by motion mapping
if (id.isNull())
{
return nullptr;
}
LLUUID remap_id = id;
if (remap_id == ANIM_AGENT_SIT_GROUND)
{
@@ -167,54 +176,100 @@ AOSet::AOState* AOSet::getStateByRemapID(const LLUUID& id)
return nullptr;
}
const LLUUID& AOSet::getAnimationForState(AOState* state) const
LLUUID AOSet::resolveAssetUUID(AOAnimation& anim)
{
if (state)
if (anim.mAssetUUID.isNull())
{
if (auto numOfAnimations = state->mAnimations.size(); numOfAnimations > 0)
LL_DEBUGS("AOEngine") << "Asset UUID for animation " << anim.mName << " not yet known, try to find it." << LL_ENDL;
if (LLViewerInventoryItem* item = gInventory.getItem(anim.mInventoryUUID))
{
if (state->mCycle)
{
if (state->mRandom)
{
state->mCurrentAnimation = (U32)(ll_frand() * numOfAnimations);
LL_DEBUGS("AOEngine") << "randomly chosen " << state->mCurrentAnimation << " of " << numOfAnimations << LL_ENDL;
}
else
{
state->mCurrentAnimation++;
if (state->mCurrentAnimation >= state->mAnimations.size())
{
state->mCurrentAnimation = 0;
}
LL_DEBUGS("AOEngine") << "cycle " << state->mCurrentAnimation << " of " << numOfAnimations << LL_ENDL;
}
}
AOAnimation& anim = state->mAnimations[state->mCurrentAnimation];
if (anim.mAssetUUID.isNull())
{
LL_DEBUGS("AOEngine") << "Asset UUID for chosen animation " << anim.mName << " not yet known, try to find it." << LL_ENDL;
if (LLViewerInventoryItem* item = gInventory.getItem(anim.mInventoryUUID))
{
LL_DEBUGS("AOEngine") << "Found asset UUID for chosen animation: " << item->getAssetUUID() << " - Updating AOAnimation.mAssetUUID" << LL_ENDL;
anim.mAssetUUID = item->getAssetUUID();
}
else
{
LL_DEBUGS("AOEngine") << "Inventory UUID " << anim.mInventoryUUID << " for chosen animation " << anim.mName << " still returns no asset." << LL_ENDL;
}
}
return anim.mAssetUUID;
LL_DEBUGS("AOEngine") << "Found asset UUID for animation: " << item->getAssetUUID() << " - Updating AOAnimation.mAssetUUID" << LL_ENDL;
anim.mAssetUUID = item->getAssetUUID();
}
else
{
LL_DEBUGS("AOEngine") << "animation state has no animations assigned" << LL_ENDL;
LL_DEBUGS("AOEngine") << "Inventory UUID " << anim.mInventoryUUID << " for animation " << anim.mName << " still returns no asset." << LL_ENDL;
}
}
return anim.mAssetUUID;
}
void AOSet::getAnimationsForState(AOState* state, uuid_vec_t& animations) const
{
if (!state)
{
return;
}
if (auto numOfSteps = state->mSteps.size(); numOfSteps > 0)
{
if (state->mCycle)
{
if (state->mRandom)
{
state->mCurrentAnimation = (U32)(ll_frand() * numOfSteps);
LL_DEBUGS("AOEngine") << "randomly chosen step " << state->mCurrentAnimation << " of " << numOfSteps << LL_ENDL;
}
else
{
state->mCurrentAnimation++;
if (state->mCurrentAnimation >= state->mSteps.size())
{
state->mCurrentAnimation = 0;
}
LL_DEBUGS("AOEngine") << "cycle step " << state->mCurrentAnimation << " of " << numOfSteps << LL_ENDL;
}
}
// steps can shrink through editing, keep the index in range
if (state->mCurrentAnimation >= state->mSteps.size())
{
state->mCurrentAnimation = 0;
}
for (AOAnimation& anim : state->mSteps[state->mCurrentAnimation].mMembers)
{
if (LLUUID assetId = resolveAssetUUID(anim); assetId.notNull())
{
animations.emplace_back(assetId);
}
}
}
else
{
LL_DEBUGS("AOEngine") << "animation state has no animations assigned" << LL_ENDL;
}
}
LLUUID AOSet::getAnimationForTrack(AOTrack& track) const
{
if (auto numOfAnimations = track.mAnimations.size(); numOfAnimations > 0)
{
if (track.mCycle)
{
if (track.mRandom)
{
track.mCurrentAnimation = (U32)(ll_frand() * numOfAnimations);
LL_DEBUGS("AOEngine") << "track " << track.mName << ": randomly chosen " << track.mCurrentAnimation << " of " << numOfAnimations << LL_ENDL;
}
else
{
track.mCurrentAnimation++;
if (track.mCurrentAnimation >= track.mAnimations.size())
{
track.mCurrentAnimation = 0;
}
LL_DEBUGS("AOEngine") << "track " << track.mName << ": cycle " << track.mCurrentAnimation << " of " << numOfAnimations << LL_ENDL;
}
}
if (track.mCurrentAnimation >= track.mAnimations.size())
{
track.mCurrentAnimation = 0;
}
return resolveAssetUUID(track.mAnimations[track.mCurrentAnimation]);
}
return LLUUID::null;
}
+29 -3
View File
@@ -64,6 +64,7 @@ public:
SwimmingForward,
SwimmingUp,
SwimmingDown,
Always,
AOSTATES_MAX
};
@@ -76,18 +77,41 @@ public:
S32 mSortOrder;
};
struct AOAnimationStep
{
std::string mName;
LLUUID mInventoryUUID;
S32 mSortOrder{ -1 };
bool mIsGroup{ false };
std::vector<AOAnimation> mMembers;
};
struct AOTrack
{
std::string mName;
LLUUID mInventoryUUID;
bool mCycle{ false };
bool mRandom{ false };
F32 mCycleTime{ 0.f };
std::vector<AOAnimation> mAnimations;
U32 mCurrentAnimation{ 0 };
LLUUID mCurrentAnimationID;
};
struct AOState
{
std::string mName;
std::vector<std::string> mAlternateNames;
std::vector<const LLInventoryItem*> mAddQueue;
S32 mNum{ 0 };
LLUUID mRemapID;
bool mCycle;
bool mRandom;
F32 mCycleTime;
std::vector<AOAnimation> mAnimations;
std::vector<AOAnimationStep> mSteps;
std::vector<AOTrack> mTracks;
U32 mCurrentAnimation;
LLUUID mCurrentAnimationID;
uuid_vec_t mCurrentAnimationIDs;
LLUUID mInventoryUUID;
bool mDirty;
};
@@ -119,7 +143,9 @@ public:
AOState* getState(S32 eName);
AOState* getStateByName(const std::string& name);
AOState* getStateByRemapID(const LLUUID& id);
const LLUUID& getAnimationForState(AOState* state) const;
void getAnimationsForState(AOState* state, uuid_vec_t& animations) const;
LLUUID getAnimationForTrack(AOTrack& track) const;
static LLUUID resolveAssetUUID(AOAnimation& anim);
void startTimer(F32 timeout);
void stopTimer();
@@ -5,8 +5,8 @@
can_resize="true"
can_dock="false"
can_close="true"
height="352"
min_height="320"
height="396"
min_height="364"
min_width="200"
layout="topleft"
name="animation_overrider"
@@ -41,13 +41,70 @@ New empty set...
Clone current set...
</floater.string>
<floater.string
name="ao_track_main">
Main
</floater.string>
<floater.string
name="ao_no_track_animations">
Empty Track - drop an animation here
</floater.string>
<floater.string
name="ao_group_tooltip">
Animation group - these play together:
</floater.string>
<floater.string
name="ao_member_tooltip">
Animation group entry - plays together with the rest of its group. Double-click to preview it alone.
</floater.string>
<floater.string
name="ao_cm_expand">
Expand
</floater.string>
<floater.string
name="ao_cm_collapse">
Collapse
</floater.string>
<floater.string
name="ao_cm_rename_group">
Rename group...
</floater.string>
<floater.string
name="ao_cm_move_out">
Move out of group
</floater.string>
<floater.string
name="ao_cm_delete">
Delete
</floater.string>
<floater.string
name="ao_dnd_merge">
Drop to group with this animation
</floater.string>
<floater.string
name="ao_dnd_add_to_group">
Drop to add to this group
</floater.string>
<floater.string
name="ao_dnd_add_to_track">
Drop to add to this track
</floater.string>
<floater.string
name="ao_dnd_folder_group">
Drop folder to create an animation group
</floater.string>
<floater.string
name="ao_dnd_folder_pour">
Drop folder to add its animations to this track
</floater.string>
<panel
name="animation_overrider_outer_panel"
filename="panel_ao.xml"
left="0"
top="16"
width="200"
height="334"
height="378"
follows="all"
layout="topleft">
</panel>
@@ -11137,6 +11137,49 @@ The name may only contain ASCII characters, excluding ":" and "|".
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="RenameAOGroup"
type="alertmodal">
Specify a new name for this animation group:
(The name may contain any ASCII character, except for ":" or "|")
<form name="form">
<input name="message" type="text" default="true">
[AO_GROUP_NAME]
</input>
<button
default="true"
index="0"
name="OK"
text="OK"/>
<button
index="1"
name="Cancel"
text="Cancel"/>
</form>
</notification>
<notification
icon="alertmodal.tga"
name="RenameAOEntryMustBeASCII"
type="alertmodal">
Could not rename to "[AO_SET_NAME]".
The name may only contain ASCII characters, excluding ":" and "|".
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="AOFolderDropNoAnimations"
type="alertmodal">
The folder "[NAME]" does not contain any animations to add.
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="NewAONameCantExist"
@@ -4,7 +4,7 @@
left="0"
top="0"
width="200"
height="314"
height="338"
follows="all"
visible="true"
layout="topleft">
@@ -16,7 +16,7 @@
left="10"
top="4"
width="180"
height="306"
height="330"
follows="all"
visible="true"
layout="topleft">
@@ -154,25 +154,36 @@
<button
name="ao_move_up"
tool_tip="Move the selected animation up in the list."
tool_tip="Move the selected animation or animation group up in the list."
left="0"
top="0"
width="20"
height="32"
height="24"
image_overlay="Arrow_Up"
follows="left|top"
layout="topleft" />
<button
name="ao_move_down"
tool_tip="Move the selected animation down in the list."
tool_tip="Move the selected animation or animation group down in the list."
top_pad="4"
width="20"
height="32"
height="24"
image_overlay="Arrow_Down"
follows="left|top"
layout="topleft" />
<button
name="ao_rename"
tool_tip="Rename the selected animation group."
left_delta="0"
bottom="-25"
width="20"
height="20"
image_overlay="Edit_Wrench"
follows="left|bottom"
layout="topleft" />
<button
name="ao_trash"
tool_tip="Remove the selected animation from the list."
@@ -185,6 +196,26 @@
layout="topleft" />
</panel>
<combo_box
name="ao_track_selection_combo"
tool_tip="Select which animation track of this state to show. The main list plays as usual, additional tracks play and cycle independently alongside it, for example a tail wag next to all walking animations."
left="0"
top_pad="4"
right="-24"
height="20"
follows="left|right|bottom"
layout="topleft" />
<button
name="ao_track_add"
tool_tip="Add a new independent animation track to this state."
left_pad="4"
width="20"
height="20"
image_overlay="AddItem_Press"
follows="right|bottom"
layout="topleft" />
<check_box
name="ao_cycle"
label="Cycle"
@@ -303,6 +334,55 @@
follows="right|bottom"
layout="topleft" />
<panel
name="ao_drop_zone_panel"
left="0"
top="68"
right="-1"
height="44"
follows="left|right|top"
visible="false"
bg_alpha_color="Black_50"
bg_opaque_color="Black_50"
background_visible="true"
background_opaque="true"
mouse_opaque="false"
layout="topleft">
<view_border
name="ao_drop_zone_border"
left="0"
top="0"
right="-1"
bottom="-1"
follows="all" />
<text
name="ao_drop_zone_add_label"
left="2"
top="6"
right="-2"
height="16"
halign="center"
font.style="BOLD"
follows="left|right|top"
layout="topleft">
Drop here to add
</text>
<text
name="ao_drop_zone_group_label"
left="2"
top_pad="2"
right="-2"
height="16"
halign="center"
follows="left|right|top"
layout="topleft">
Drop on existing to group
</text>
</panel>
</panel>
<!-- Reload Cover Panel -->
@@ -312,7 +392,7 @@
left="0"
top="0"
width="200"
height="315"
height="339"
follows="all"
visible="false"
bg_alpha_color="Black_50"
@@ -5,4 +5,18 @@
<floater.string name="ao_dnd_only_on_full_interface">Możesz przeciągać notkę z zestawami animacji tylko na pełne okno interfejsu Animatora. Kliknij na ikonce klucza francuskiego, aby je otworzyć.</floater.string>
<floater.string name="ao_add_blank_label">Nowy pusty zestaw...</floater.string>
<floater.string name="ao_add_clone_label">Sklonuj obecny zestaw...</floater.string>
<floater.string name="ao_track_main">Główna</floater.string>
<floater.string name="ao_no_track_animations">Pusta ścieżka - upuść tutaj animację</floater.string>
<floater.string name="ao_group_tooltip">Grupa animacji - te animacje są odtwarzane razem:</floater.string>
<floater.string name="ao_member_tooltip">Element grupy animacji - odtwarza się razem z resztą swojej grupy. Kliknij dwukrotnie, aby wyświetlić podgląd samodzielnie.</floater.string>
<floater.string name="ao_cm_expand">Rozwiń</floater.string>
<floater.string name="ao_cm_collapse">Zwiń</floater.string>
<floater.string name="ao_cm_rename_group">Zmień nazwę grupy...</floater.string>
<floater.string name="ao_cm_move_out">Przenieś poza grupę</floater.string>
<floater.string name="ao_cm_delete">Usuń</floater.string>
<floater.string name="ao_dnd_merge">Upuść, aby zgrupować z tą animacją</floater.string>
<floater.string name="ao_dnd_add_to_group">Upuść, aby dodać do tej grupy</floater.string>
<floater.string name="ao_dnd_add_to_track">Upuść, aby dodać do tej ścieżki</floater.string>
<floater.string name="ao_dnd_folder_group">Upuść folder, aby utworzyć grupę animacji</floater.string>
<floater.string name="ao_dnd_folder_pour">Upuść folder, aby dodać jego animacje do tej ścieżki</floater.string>
</floater>
@@ -4149,6 +4149,23 @@ Nazwa może zawierać tylko znaki ASCII, za wyjątkiem ":" oraz "|".
Nie można zmienić nazwy zestawu AO "[AO_SET_NAME]".
Nazwa może zawierać tylko znaki ASCII, za wyjątkiem ":" oraz "|".
</notification>
<notification name="RenameAOGroup">
Wpisz nazwę nowej grupy animacji:
(Nazwa może zawierać każdy znak ASCII, za wyjątkiem ":" oraz "|")
<form name="form">
<input name="message">
[AO_GROUP_NAME]
</input>
<button name="Cancel" text="Anuluj"/>
</form>
</notification>
<notification name="RenameAOEntryMustBeASCII">
Nie można zmienić nazwy na "[AO_SET_NAME]".
Nazwa może zawierać tylko znaki ASCII, za wyjątkiem ":" oraz "|".
</notification>
<notification name="AOFolderDropNoAnimations">
Folder "[NAME]" nie zawiera żadnych animacji do dodania.
</notification>
<notification name="NewAONameCantExist">
Zestaw animacji o tej nazwie już istnieje.
</notification>
@@ -11,10 +11,13 @@
<check_box name="ao_disable_stands_in_mouselook" label="Wyłącz w trybie 1 osoby" tool_tip="Jeśli chcesz zachować własną animację stania w miejscu, będąc w trybie pierwszoosobowym (mouselook), to zaznacz tą opcję." />
<combo_box name="ao_state_selection_combo" tool_tip="Wybierz stan animacji do edycji." />
<panel name="ao_animation_move_trash_panel">
<button name="ao_move_up" tool_tip="Przenieś zaznaczoną animację do góry na liście." />
<button name="ao_move_down" tool_tip="Przenieś zaznaczoną animację w dół na liście." />
<button name="ao_move_up" tool_tip="Przenieś zaznaczoną animację lub grupę animacji do góry na liście." />
<button name="ao_move_down" tool_tip="Przenieś zaznaczoną animację lub grupę animacji w dół na liście." />
<button name="ao_rename" tool_tip="Zmień nazwę wybranej grupy animacji." />
<button name="ao_trash" tool_tip="Usuń zaznaczoną animację z listy." />
</panel>
<combo_box name="ao_track_selection_combo" tool_tip="Wybierz, która ścieżka animacji tego stanu ma być wyświetlana. Lista główna jest odtwarzana jak zwykle, natomiast dodatkowe ścieżki są odtwarzane i zapętlane niezależnie obok niej, na przykład machanie ogonem działa podczas wszystkich animacji chodzenia." />
<button name="ao_track_add" tool_tip="Dodaj nową niezależną ścieżkę animacji do tego stanu." />
<check_box name="ao_cycle" label="Cykl" tool_tip="Odtwarzaj inną animację z listy za każdym razem, gdy dany stan jest wywoływany." />
<check_box name="ao_randomize" label="Losowy porządek" tool_tip="Losuj porządek odtwarzania animacji w cyklu." />
<text name="ao_cycle_time_seconds_label" value="Czas cyklu (sekundy):" />
@@ -29,6 +32,14 @@
</layout_panel>
</layout_stack>
<button name="ao_less" tool_tip="Pokazuj mniejszy interfejs Animatora." />
<panel name="ao_drop_zone_panel">
<text name="ao_drop_zone_add_label">
Upuść tutaj, by dodać
</text>
<text name="ao_drop_zone_group_label">
Upuść na istniejącą, by zgrupować
</text>
</panel>
</panel>
<panel name="ao_reload_cover">
<panel name="ao_reload_text_panel">