diff --git a/Aquaria/AnimationEditor.cpp b/Aquaria/AnimationEditor.cpp index 1f07d73..0b15386 100644 --- a/Aquaria/AnimationEditor.cpp +++ b/Aquaria/AnimationEditor.cpp @@ -1311,6 +1311,8 @@ void AnimationEditor::moveNextWidgets(float dt) void AnimationEditor::toggleRenderBorders() { + if (dsq->isNested()) return; + renderBorders = !renderBorders; updateRenderBorders(); } @@ -1336,18 +1338,24 @@ void AnimationEditor::updateEditingBone() void AnimationEditor::showAllBones() { + if (dsq->isNested()) return; + for (size_t i = 0; i < editSprite->bones.size(); ++i) editSprite->bones[i]->renderQuad = true; } void AnimationEditor::incrTimelineUnit() { + if (dsq->isNested()) return; + TIMELINE_UNIT += TIMELINE_UNIT_STEP; updateTimelineUnit(); } void AnimationEditor::decrTimelineUnit() { + if (dsq->isNested()) return; + float t = TIMELINE_UNIT - TIMELINE_UNIT_STEP; if (t >= TIMELINE_UNIT_STEP) TIMELINE_UNIT = t; @@ -1363,12 +1371,16 @@ void AnimationEditor::updateTimelineUnit() void AnimationEditor::incrTimelineGrid() { + if (dsq->isNested()) return; + TIMELINE_GRIDSIZE++; updateTimelineGrid(); } void AnimationEditor::decrTimelineGrid() { + if (dsq->isNested()) return; + int t = TIMELINE_GRIDSIZE - 1; if (t > 0) TIMELINE_GRIDSIZE = t; diff --git a/Aquaria/Avatar.cpp b/Aquaria/Avatar.cpp index afdb7ee..c2d43f5 100644 --- a/Aquaria/Avatar.cpp +++ b/Aquaria/Avatar.cpp @@ -44,8 +44,6 @@ bool lastJumpOutFromWaterBubble = false; bool useSpiritDistance = true; bool inSpiritWorld = false; -const int LAYER_FLOURISH = 3; - const float MULT_DMG_CRABCOSTUME = 0.75; const float MULT_DMG_FISHFORM = 1.5; const float MULT_DMG_SEAHORSEARMOR = 0.6; @@ -134,9 +132,6 @@ bool _isUnderWater; //HRECORD avatarRecord = 0; -#define ANIMLAYER_OVERRIDE 4 -#define ANIMLAYER_UPPERBODYIDLE 6 -#define ANIMLAYER_HEADOVERRIDE 7 Vector Target::getWorldPosition() { @@ -843,7 +838,7 @@ void Avatar::startFlourish() flourishTimer.start(fanim->getAnimationLength()-0.2f); flourishPowerTimer.start(fanim->getAnimationLength()*0.5f); } - skeletalSprite.transitionAnimate(anim, 0.1, 0, LAYER_FLOURISH); + skeletalSprite.transitionAnimate(anim, 0.1, 0, ANIMLAYER_FLOURISH); flourish = true; float rotz = rotationOffset.z; @@ -2688,7 +2683,7 @@ bool Avatar::fireAtNearestValidEntity(const std::string &shot) - skeletalSprite.transitionAnimate("fireBlast", 0.1, 0, 5); + skeletalSprite.transitionAnimate("fireBlast", 0.1, 0, ANIMLAYER_ARMOVERRIDE); s->position = p; //s->damageType = dt; /* @@ -2918,7 +2913,7 @@ void Avatar::formAbility(int ability) else doShock("EnergyTendril"); if (!state.lockedToWall) - skeletalSprite.animate("energyChargeAttack", 0, 6); + skeletalSprite.animate("energyChargeAttack", 0, ANIMLAYER_UPPERBODYIDLE); /* if (core->afterEffectManager) @@ -3311,7 +3306,7 @@ void Avatar::doShock(const std::string &shotName) int thits = getNumShots(); /* - if (skeletalSprite.getAnimationLayer(LAYER_FLOURISH)->getCurrentAnimation()) + if (skeletalSprite.getAnimationLayer(ANIMLAYER_FLOURISH)->getCurrentAnimation()) { thits = maxTendrilHits; } @@ -8889,7 +8884,7 @@ void Avatar::onUpdate(float dt) std::ostringstream os; os << "swimExtra-" << anim; - skeletalSprite.transitionAnimate(os.str(), 0.5, 0, 6); + skeletalSprite.transitionAnimate(os.str(), 0.5, 0, ANIMLAYER_UPPERBODYIDLE); } } } diff --git a/Aquaria/Avatar.h b/Aquaria/Avatar.h index a77f7f8..fbd1448 100644 --- a/Aquaria/Avatar.h +++ b/Aquaria/Avatar.h @@ -59,6 +59,16 @@ enum EnableInputType AVATARINPUT_MAX }; +enum AvatarAnimLayers +{ + ANIMLAYER_FLOURISH = 3, + ANIMLAYER_OVERRIDE = 4, + ANIMLAYER_ARMOVERRIDE = 5, + ANIMLAYER_UPPERBODYIDLE = 6, + ANIMLAYER_HEADOVERRIDE = 7, + ANIMLAYER_MAX +}; + class SongIconParticle : public Quad { public: diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index 578fa76..e3e60f0 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -1981,7 +1981,8 @@ void DSQ::setInputMode(InputMode mode) void DSQ::toggleRenderCollisionShapes() { - RenderObject::renderCollisionShape = !RenderObject::renderCollisionShape; + if (core->getCtrlState() && core->getShiftState()) + RenderObject::renderCollisionShape = !RenderObject::renderCollisionShape; } void DSQ::takeScreenshot() @@ -4137,13 +4138,11 @@ void DSQ::bindInput() #endif if (isDeveloperKeys()) { -#if defined(BBGE_BUILD_WINDOWS) || defined(BBGE_BUILD_UNIX) - addAction(MakeFunctionEvent(DSQ, instantQuit), KEY_Q, 1); #ifdef AQUARIA_BUILD_CONSOLE addAction(MakeFunctionEvent(DSQ, toggleConsole), KEY_TILDE, 0); #endif -#endif - addAction(MakeFunctionEvent(DSQ, toggleRenderCollisionShapes), KEY_CAPSLOCK, 0); + addAction(MakeFunctionEvent(DSQ, instantQuit), KEY_Q, 1); + addAction(MakeFunctionEvent(DSQ, toggleRenderCollisionShapes), KEY_RETURN, 0); } addAction(MakeFunctionEvent(DSQ, debugMenu), KEY_BACKSPACE, 0); #if BBGE_BUILD_SDL @@ -4879,6 +4878,8 @@ std::string DSQ::getSaveDirectory() ParticleEffect *DSQ::spawnParticleEffect(const std::string &name, Vector position, float rotz, float t, int layer, float follow) { + if (name.empty()) + return NULL; if (t!=0) { PECue p(name, position, rotz, t); diff --git a/Aquaria/Game.cpp b/Aquaria/Game.cpp index ff563ac..ff65463 100644 --- a/Aquaria/Game.cpp +++ b/Aquaria/Game.cpp @@ -5806,7 +5806,7 @@ Entity* Game::setActivePet(int flag) void Game::createLi() { - int liFlag = dsq->continuity.getFlag(1000); + int liFlag = dsq->continuity.getFlag(FLAG_LI); std::ostringstream os; os << "liFlag: " << liFlag; debugLog(os.str()); diff --git a/Aquaria/SceneEditor.cpp b/Aquaria/SceneEditor.cpp index e35557e..17d63e5 100644 --- a/Aquaria/SceneEditor.cpp +++ b/Aquaria/SceneEditor.cpp @@ -3370,9 +3370,12 @@ void SceneEditor::updateText() os << "entities (" << dsq->entities.size() << ")"; if (editingEntity) { - os << " id: " << editingEntity->getID() << " name: " << editingEntity->name << " flag: " << dsq->continuity.getEntityFlag(dsq->game->sceneName, editingEntity->getID()); - os << " groupID: " << editingEntity->getGroupID() << " "; - os << " state: " << editingEntity->getState(); + os << " id: " << editingEntity->getID() + << " name: " << editingEntity->name + << " flag:" << dsq->continuity.getEntityFlag(dsq->game->sceneName, editingEntity->getID()) + << " fh:" << editingEntity->isfh() + << " fv:" << editingEntity->isfv() + << " state:" << editingEntity->getState(); } break; case ET_PATHS: diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index d493110..a39fd95 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -863,6 +863,12 @@ luaFunc(obj_getRotation) luaReturnNum(r ? r->rotation.z : 0.0f); } +luaFunc(obj_getRotationOffset) +{ + RenderObject *r = robj(L); + luaReturnNum(r ? r->rotationOffset.z : 0.0f); +} + luaFunc(obj_offset) { RenderObject *r = robj(L); @@ -887,6 +893,15 @@ luaFunc(obj_internalOffset) luaReturnNil(); } +luaFunc(obj_getInternalOffset) +{ + RenderObject *r = robj(L); + Vector io; + if (r) + io = r->internalOffset; + luaReturnVec2(io.x, io.y); +} + luaFunc(obj_getPosition) { float x=0,y=0; @@ -1440,10 +1455,12 @@ luaFunc(quad_setHeight) RO_FUNC(getter, prefix, rotate ) \ RO_FUNC(getter, prefix, rotateOffset ) \ RO_FUNC(getter, prefix, getRotation ) \ + RO_FUNC(getter, prefix, getRotationOffset) \ RO_FUNC(getter, prefix, isRotating ) \ RO_FUNC(getter, prefix, offset ) \ RO_FUNC(getter, prefix, getOffset ) \ RO_FUNC(getter, prefix, internalOffset ) \ + RO_FUNC(getter, prefix, getInternalOffset) \ RO_FUNC(getter, prefix, getPosition ) \ RO_FUNC(getter, prefix, x ) \ RO_FUNC(getter, prefix, y ) \ @@ -3233,16 +3250,30 @@ luaFunc(entity_initStrands) luaFunc(entity_initSkeletal) { - ScriptedEntity *e = scriptedEntity(L); - e->renderQuad = false; - e->setWidthHeight(128, 128); - e->skeletalSprite.loadSkeletal(getString(L, 2)); - const char *s = lua_tostring(L, 3); - if (s && *s) - e->skeletalSprite.loadSkin(s); + Entity *e = entity(L); + if (e) + { + e->renderQuad = false; + e->setWidthHeight(128, 128); + e->skeletalSprite.loadSkeletal(getString(L, 2)); + const char *s = lua_tostring(L, 3); + if (s && *s) + e->skeletalSprite.loadSkin(s); + } luaReturnNil(); } +luaFunc(entity_loadSkin) +{ + Entity *e = entity(L); + if (e && e->skeletalSprite.isLoaded()) + { + const char *s = lua_tostring(L, 2); + if (s && *s) + e->skeletalSprite.loadSkin(s); + } + luaReturnNil(); +} luaFunc(entity_idle) { @@ -3296,6 +3327,18 @@ luaFunc(entity_animate) luaReturnNum(ret); } +luaFunc(entity_stopAnimation) +{ + SkeletalSprite *skel = getSkeletalSprite(entity(L)); + if (skel) + { + AnimationLayer *animlayer = skel->getAnimationLayer(lua_tointeger(L, 2)); + if (animlayer) + animlayer->stopAnimation(); + } + luaReturnNil(); +} + // entity, x, y, time, ease, relative luaFunc(entity_move) { @@ -5658,7 +5701,7 @@ luaFunc(entity_pullEntities) if (e) { Vector pos(lua_tonumber(L, 2), lua_tonumber(L, 3)); - int range = lua_tonumber(L, 4); + float range = lua_tonumber(L, 4); float len = lua_tonumber(L, 5); float dt = lua_tonumber(L, 6); FOR_ENTITIES(i) @@ -6246,13 +6289,13 @@ luaFunc(toggleVersionLabel) luaFunc(setVersionLabelText) { dsq->setVersionLabelText(); - luaReturnPtr(NULL); + luaReturnNil(); } luaFunc(setCutscene) { dsq->setCutscene(getBool(L, 1), getBool(L, 2)); - luaReturnPtr(NULL); + luaReturnNil(); } luaFunc(isInCutscene) @@ -6788,7 +6831,7 @@ luaFunc(entity_setWeight) { CollideEntity *e = collideEntity(L); if (e) - e->weight = lua_tointeger(L, 2); + e->weight = lua_tonumber(L, 2); luaReturnNil(); } @@ -6885,6 +6928,13 @@ luaFunc(isObstructed) luaReturnBool(dsq->game->isObstructed(TileVector(Vector(x,y)))); } +luaFunc(getObstruction) +{ + int x = lua_tonumber(L, 1); + int y = lua_tonumber(L, 2); + luaReturnInt(dsq->game->getGrid(TileVector(Vector(x,y)))); +} + luaFunc(isObstructedBlock) { int x = lua_tonumber(L, 1); @@ -7099,21 +7149,24 @@ luaFunc(createBitmapText) luaFunc(text_setText) { BaseText *txt = getText(L); - txt->setText(getString(L, 2)); + if (txt) + txt->setText(getString(L, 2)); luaReturnNil(); } luaFunc(text_setFontSize) { BaseText *txt = getText(L); - txt->setFontSize(lua_tointeger(L, 2)); + if (txt) + txt->setFontSize(lua_tointeger(L, 2)); luaReturnNil(); } luaFunc(text_setWidth) { BaseText *txt = getText(L); - txt->setWidth(lua_tointeger(L, 2)); + if (txt) + txt->setWidth(lua_tointeger(L, 2)); luaReturnNil(); } @@ -7408,6 +7461,7 @@ static const struct { luaRegister(entity_initSegments), luaRegister(entity_warpSegments), luaRegister(entity_initSkeletal), + luaRegister(entity_loadSkin), luaRegister(entity_initStrands), luaRegister(entity_hurtTarget), @@ -7453,6 +7507,7 @@ static const struct { luaRegister(entity_doCollisionAvoidance), luaRegister(entity_animate), luaRegister(entity_setAnimLayerTimeMult), + luaRegister(entity_stopAnimation), luaRegister(entity_setCurrentTarget), luaRegister(entity_stopInterpolating), @@ -7610,6 +7665,7 @@ static const struct { luaRegister(castSong), luaRegister(isObstructed), luaRegister(isObstructedBlock), + luaRegister(getObstruction), luaRegister(isFlag), @@ -8625,6 +8681,12 @@ static const struct { luaConstant(INPUT_MOUSE), luaConstant(INPUT_JOYSTICK), luaConstant(INPUT_KEYBOARD), + + luaConstant(ANIMLAYER_FLOURISH), + luaConstant(ANIMLAYER_OVERRIDE), + luaConstant(ANIMLAYER_ARMOVERRIDE), + luaConstant(ANIMLAYER_UPPERBODYIDLE), + luaConstant(ANIMLAYER_HEADOVERRIDE), }; //============================================================================================ diff --git a/BBGE/Base.h b/BBGE/Base.h index a0c7140..0cd1cc2 100644 --- a/BBGE/Base.h +++ b/BBGE/Base.h @@ -120,6 +120,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #pragma warning(disable:4189) // UqqqqSEFUL: local variable is initialized but not referenced #endif +#undef GetCharWidth + #include #include diff --git a/BBGE/RenderObject.cpp b/BBGE/RenderObject.cpp index fa9acdc..032c4c8 100644 --- a/BBGE/RenderObject.cpp +++ b/BBGE/RenderObject.cpp @@ -965,13 +965,15 @@ void RenderObject::renderCollision() } else if (collideRadius > 0) { - /* glPushMatrix(); + glLoadIdentity(); + core->setupRenderPositionAndScale(); glBindTexture(GL_TEXTURE_2D, 0); - //glScalef(-scale.x, -scale.y, 0); - glTranslatef(-offset.x, -offset.y,0); + glTranslatef(position.x+offset.x, position.y+offset.y, 0); + //glScalef(scale.x, scale.y, 0); + glTranslatef(internalOffset.x, internalOffset.y, 0); glEnable(GL_BLEND); - glTranslatef(collidePosition.x, collidePosition.y,0); + //glTranslatef(collidePosition.x, collidePosition.y,0); //glEnable(GL_ALPHA_TEST); //glAlphaFunc(GL_GREATER, 0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -980,7 +982,6 @@ void RenderObject::renderCollision() glDisable(GL_BLEND); glTranslatef(offset.x, offset.y,0); glPopMatrix(); - */ } } diff --git a/BBGE/Texture.cpp b/BBGE/Texture.cpp index d4234f9..c1cd58e 100644 --- a/BBGE/Texture.cpp +++ b/BBGE/Texture.cpp @@ -69,7 +69,6 @@ Texture::Texture() : Resource() repeat = false; repeating = false; pngSetStandardOrientation(0); - imageData = 0; ow = oh = -1; } @@ -318,6 +317,7 @@ void Texture::load(std::string file) file = core->adjustFilenameCase(file); loadName = file; + repeating = false; size_t pos = file.find_last_of('.'); diff --git a/BBGE/Texture.h b/BBGE/Texture.h index 44b6cf2..c2de4bd 100644 --- a/BBGE/Texture.h +++ b/BBGE/Texture.h @@ -73,9 +73,7 @@ public: #ifdef BBGE_BUILD_DIRECTX LPDIRECT3DTEXTURE9 d3dTexture; #endif - //void setImageData(imageData); - // HACK: - unsigned char *imageData; + void reload(); static TexErr textureError; diff --git a/ExternalLibs/glfont2/glfont2.cpp b/ExternalLibs/glfont2/glfont2.cpp index 3f34acb..0e497c2 100644 --- a/ExternalLibs/glfont2/glfont2.cpp +++ b/ExternalLibs/glfont2/glfont2.cpp @@ -19,7 +19,6 @@ using namespace std; #endif #include */ -#include "Base.h" #include "SDL_endian.h" @@ -91,10 +90,6 @@ bool GLFont::Create (const char *file_name, int tex, bool loadTexture) header.end_char = read_int(input); input.seekg(4, ios::cur); // skip chars field - std::ostringstream os; - os << "tex_width: " << header.tex_width << " tex_height: " << header.tex_height; - debugLog(os.str()); - //Allocate space for character array num_chars = header.end_char - header.start_char + 1; if ((header.chars = new GLFontChar[num_chars]) == NULL) diff --git a/aquaria.ico b/aquaria.ico new file mode 100644 index 0000000..ba4566a Binary files /dev/null and b/aquaria.ico differ diff --git a/aquaria.rc b/aquaria.rc new file mode 100644 index 0000000..901113e --- /dev/null +++ b/aquaria.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "aquaria.ico" diff --git a/win/Aquaria_vc90.sln b/win/Aquaria_vc90.sln new file mode 100644 index 0000000..eb69167 --- /dev/null +++ b/win/Aquaria_vc90.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Aquaria", "vc90\Aquaria.vcproj", "{4DB6D5AA-4EAD-4195-9B54-389B558036D8}" + ProjectSection(ProjectDependencies) = postProject + {4C2AD812-6776-4728-A4B0-ABA397224152} = {4C2AD812-6776-4728-A4B0-ABA397224152} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BBGE", "vc90\BBGE.vcproj", "{4C2AD812-6776-4728-A4B0-ABA397224152}" + ProjectSection(ProjectDependencies) = postProject + {6A2DACD7-DA30-49A1-9214-CCDEB48E6050} = {6A2DACD7-DA30-49A1-9214-CCDEB48E6050} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "external", "vc90\external.vcproj", "{6A2DACD7-DA30-49A1-9214-CCDEB48E6050}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DB6D5AA-4EAD-4195-9B54-389B558036D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {4DB6D5AA-4EAD-4195-9B54-389B558036D8}.Debug|Win32.Build.0 = Debug|Win32 + {4DB6D5AA-4EAD-4195-9B54-389B558036D8}.Release|Win32.ActiveCfg = Release|Win32 + {4DB6D5AA-4EAD-4195-9B54-389B558036D8}.Release|Win32.Build.0 = Release|Win32 + {4C2AD812-6776-4728-A4B0-ABA397224152}.Debug|Win32.ActiveCfg = Debug|Win32 + {4C2AD812-6776-4728-A4B0-ABA397224152}.Debug|Win32.Build.0 = Debug|Win32 + {4C2AD812-6776-4728-A4B0-ABA397224152}.Release|Win32.ActiveCfg = Release|Win32 + {4C2AD812-6776-4728-A4B0-ABA397224152}.Release|Win32.Build.0 = Release|Win32 + {6A2DACD7-DA30-49A1-9214-CCDEB48E6050}.Debug|Win32.ActiveCfg = Debug|Win32 + {6A2DACD7-DA30-49A1-9214-CCDEB48E6050}.Debug|Win32.Build.0 = Debug|Win32 + {6A2DACD7-DA30-49A1-9214-CCDEB48E6050}.Release|Win32.ActiveCfg = Release|Win32 + {6A2DACD7-DA30-49A1-9214-CCDEB48E6050}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win/vc90/Aquaria.vcproj b/win/vc90/Aquaria.vcproj new file mode 100644 index 0000000..6941a21 --- /dev/null +++ b/win/vc90/Aquaria.vcproj @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/vc90/BBGE.vcproj b/win/vc90/BBGE.vcproj new file mode 100644 index 0000000..a335f92 --- /dev/null +++ b/win/vc90/BBGE.vcproj @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/vc90/external.vcproj b/win/vc90/external.vcproj new file mode 100644 index 0000000..11f0025 --- /dev/null +++ b/win/vc90/external.vcproj @@ -0,0 +1,1379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +