Update Stone Pillar graphic. Update Stone Pillar Monster data. Include a do nothing strategy. Implement immovable property for monsters. Implement Invulnerable property for monsters. Implement lifetime property for monsters. Include a fadeout timer for when the lifetime expires. Implement capability for monsters to be deleted from the map. Release Build 9271.

pull/57/head
sigonasr2 7 months ago
parent 39303e2438
commit c2b2652810
  1. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 10
      Adventures in Lestoria/AdventuresInLestoria.cpp
  3. 2
      Adventures in Lestoria/AdventuresInLestoria.h
  4. 41
      Adventures in Lestoria/Do_Nothing.cpp
  5. 37
      Adventures in Lestoria/Monster.cpp
  6. 8
      Adventures in Lestoria/Monster.h
  7. 1
      Adventures in Lestoria/RUN_STRATEGY.cpp
  8. 2
      Adventures in Lestoria/Version.h
  9. 4
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  10. 12
      Adventures in Lestoria/assets/config/Monsters.txt
  11. 48
      Adventures in Lestoria/assets/config/credits.txt
  12. BIN
      Adventures in Lestoria/assets/gamepack.pak
  13. BIN
      x64/Release/Adventures in Lestoria.exe

@ -693,6 +693,10 @@
<ClCompile Include="discord-files\types.cpp" /> <ClCompile Include="discord-files\types.cpp" />
<ClCompile Include="discord-files\user_manager.cpp" /> <ClCompile Include="discord-files\user_manager.cpp" />
<ClCompile Include="discord-files\voice_manager.cpp" /> <ClCompile Include="discord-files\voice_manager.cpp" />
<ClCompile Include="Do_Nothing.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="drawutil.cpp" /> <ClCompile Include="drawutil.cpp" />
<ClCompile Include="DynamicCounter.cpp"> <ClCompile Include="DynamicCounter.cpp">
<SubType> <SubType>

@ -3951,6 +3951,10 @@ rcode AiL::LoadResource(Renderable&renderable,std::string_view imgPath,bool filt
void AiL::UpdateMonsters(){ void AiL::UpdateMonsters(){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(m->markedForDeletion){
AMonsterIsMarkedForDeletion();
continue;
}
m->Update(game->GetElapsedTime()); m->Update(game->GetElapsedTime());
} }
for(Monster&m:game->monstersToBeSpawned){ for(Monster&m:game->monstersToBeSpawned){
@ -3958,6 +3962,8 @@ void AiL::UpdateMonsters(){
MONSTER_LIST.push_back(std::make_unique<Monster>(m)); MONSTER_LIST.push_back(std::make_unique<Monster>(m));
if(MONSTER_LIST.capacity()>prevCapacity)LOG(std::format("WARNING! The monster list has automatically reserved more space and resized to {}! This caused one potential frame where bullet/effect hitlists that stored information on what monsters were hit to potentially be hit a second time or cause monsters that should've been hit to never be hit. Consider starting with a larger default reserved size for MONSTER_LIST if your intention was to have this many monsters!",MONSTER_LIST.capacity())); if(MONSTER_LIST.capacity()>prevCapacity)LOG(std::format("WARNING! The monster list has automatically reserved more space and resized to {}! This caused one potential frame where bullet/effect hitlists that stored information on what monsters were hit to potentially be hit a second time or cause monsters that should've been hit to never be hit. Consider starting with a larger default reserved size for MONSTER_LIST if your intention was to have this many monsters!",MONSTER_LIST.capacity()));
} }
if(aMonsterIsMarkedForDeletion)std::erase_if(MONSTER_LIST,[](const std::unique_ptr<Monster>&m){return m->markedForDeletion;});
aMonsterIsMarkedForDeletion=false;
game->monstersToBeSpawned.clear(); game->monstersToBeSpawned.clear();
} }
@ -4078,3 +4084,7 @@ void AiL::UpdateEntities(){
ItemDrop::UpdateDrops(GetElapsedTime()); ItemDrop::UpdateDrops(GetElapsedTime());
UpdateBullets(GetElapsedTime()); UpdateBullets(GetElapsedTime());
} }
void AiL::AMonsterIsMarkedForDeletion(){
aMonsterIsMarkedForDeletion=true;
}

@ -168,6 +168,7 @@ private:
States::State transitionState=States::State::GAME_RUN; States::State transitionState=States::State::GAME_RUN;
bool gameEnd=false; bool gameEnd=false;
std::vector<Monster>monstersToBeSpawned; std::vector<Monster>monstersToBeSpawned;
bool aMonsterIsMarkedForDeletion=false; //DO NOT MODIFY DIRECTLY! Use AMonsterIsMarkedForDeletion() instead!
time_t gameStarted; time_t gameStarted;
std::function<void(std::string_view)>responseCallback; std::function<void(std::string_view)>responseCallback;
float fadeInDuration=0; float fadeInDuration=0;
@ -338,6 +339,7 @@ public:
void ResetCompletedStageFlag(); void ResetCompletedStageFlag();
void UpdateEntities(); void UpdateEntities();
Minimap minimap; Minimap minimap;
void AMonsterIsMarkedForDeletion(); //The way this is implemented is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.
struct TileGroupData{ struct TileGroupData{
vi2d tilePos; vi2d tilePos;

@ -0,0 +1,41 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "Monster.h"
void Monster::STRATEGY::DONOTHING(Monster&m,float fElapsedTime,std::string strategy){}

@ -65,7 +65,7 @@ safemap<std::string,std::function<void(Monster&,float,std::string)>>STRATEGY_DAT
std::map<std::string,Renderable*>MonsterData::imgs; std::map<std::string,Renderable*>MonsterData::imgs;
Monster::Monster(vf2d pos,MonsterData data,bool upperLevel,bool bossMob): Monster::Monster(vf2d pos,MonsterData data,bool upperLevel,bool bossMob):
pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(Direction::SOUTH){ pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(Direction::SOUTH),lifetime(GetTotalLifetime()){
for(const std::string&anim:data.GetAnimations()){ for(const std::string&anim:data.GetAnimations()){
animation.AddState(anim,ANIMATION_DATA[std::format("{}_{}",name,anim)]); animation.AddState(anim,ANIMATION_DATA[std::format("{}_{}",name,anim)]);
} }
@ -269,6 +269,20 @@ bool Monster::Update(float fElapsedTime){
lastFacingDirectionChange+=fElapsedTime; lastFacingDirectionChange+=fElapsedTime;
timeSpentAlive+=fElapsedTime; timeSpentAlive+=fElapsedTime;
#pragma region Handle Monster Lifetime and fade timer.
if(fadeTimer>0.f){
fadeTimer=std::max(0.f,fadeTimer-fElapsedTime);
if(fadeTimer==0.f)MarkForDeletion();
}else
if(GetLifetime().has_value()){
lifetime.value()=std::max(0.f,lifetime.value()-fElapsedTime);
if(lifetime.value()==0.f){
fadeTimer=1.f;
lifetime={}; //Nullify the lifetime value as the monster has expired. So we'll prevent a loop by doing this.
}
}
#pragma endregion
if(size!=targetSize){ if(size!=targetSize){
if(size>targetSize){ if(size>targetSize){
size=std::max(targetSize,size-AiL::SIZE_CHANGE_SPEED*fElapsedTime); size=std::max(targetSize,size-AiL::SIZE_CHANGE_SPEED*fElapsedTime);
@ -323,12 +337,13 @@ bool Monster::Update(float fElapsedTime){
geom2d::line line(pos,m->GetPos()); geom2d::line line(pos,m->GetPos());
float dist = line.length(); float dist = line.length();
m->SetPos(line.rpoint(dist*1.1f)); m->SetPos(line.rpoint(dist*1.1f));
if(m->IsAlive()){ if(!Immovable()&&m->IsAlive()){
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
} }
} }
if(!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){ if(!Immovable()&&
!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
geom2d::line line(pos,game->GetPlayer()->GetPos()); geom2d::line line(pos,game->GetPlayer()->GetPos());
float dist = line.length(); float dist = line.length();
SetPos(line.rpoint(-0.1f)); SetPos(line.rpoint(-0.1f));
@ -400,9 +415,14 @@ void Monster::Draw()const{
} }
const bool NotOnTitleScreen=GameState::STATE!=GameState::states[States::MAIN_MENU]; const bool NotOnTitleScreen=GameState::STATE!=GameState::states[States::MAIN_MENU];
uint8_t blendColAlpha=255U;
if(NotOnTitleScreen if(NotOnTitleScreen
&&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendCol.a=160; &&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendColAlpha=160;
if(fadeTimer>0.f)blendColAlpha=uint8_t(util::lerp(0,blendCol.a,fadeTimer)); //Fade timer goes from 1 to 0 seconds.
blendCol.a=blendColAlpha;
game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol); game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
if(overlaySprite.length()!=0){ if(overlaySprite.length()!=0){
@ -559,7 +579,7 @@ const bool Monster::AttackAvoided(const float attackZ)const{
} }
bool Monster::Hurt(int damage,bool onUpperLevel,float z){ bool Monster::Hurt(int damage,bool onUpperLevel,float z){
if(!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z)) return false; if(Invulnerable()||!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z)) return false;
if(game->InBossEncounter()){ if(game->InBossEncounter()){
game->StartBossEncounter(); game->StartBossEncounter();
} }
@ -1011,8 +1031,15 @@ const bool Monster::Invulnerable()const{
return MONSTER_DATA.at(GetName()).Invulnerable(); return MONSTER_DATA.at(GetName()).Invulnerable();
} }
const std::optional<float>Monster::GetLifetime()const{ const std::optional<float>Monster::GetLifetime()const{
return lifetime;
}
const std::optional<float>Monster::GetTotalLifetime()const{
return MONSTER_DATA.at(GetName()).GetLifetime(); return MONSTER_DATA.at(GetName()).GetLifetime();
} }
const std::optional<float>Monster::GetCollisionRadius()const{ const std::optional<float>Monster::GetCollisionRadius()const{
return MONSTER_DATA.at(GetName()).GetCollisionRadius(); return MONSTER_DATA.at(GetName()).GetCollisionRadius();
} }
void Monster::MarkForDeletion(){
markedForDeletion=true;
}

@ -168,9 +168,13 @@ public:
const bool Invulnerable()const; const bool Invulnerable()const;
//If an object has a lifetime set, returns it. //If an object has a lifetime set, returns it.
const std::optional<float>GetLifetime()const; const std::optional<float>GetLifetime()const;
const std::optional<float>GetTotalLifetime()const;
//If an object has a collision radius, returns it. //If an object has a collision radius, returns it.
const std::optional<float>GetCollisionRadius()const; const std::optional<float>GetCollisionRadius()const;
private: private:
//NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
// The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.
void MarkForDeletion();
std::string name; std::string name;
vf2d pos; vf2d pos;
vf2d vel={0,0}; vf2d vel={0,0};
@ -240,6 +244,9 @@ private:
std::vector<DeathSpawnInfo>deathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster. std::vector<DeathSpawnInfo>deathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster.
vf2d mountedSprOffset{}; vf2d mountedSprOffset{};
float timeSpentAlive{0.f}; float timeSpentAlive{0.f};
std::optional<float>lifetime{};
float fadeTimer{0.f};
bool markedForDeletion{false}; //DO NOT MODIFY DIRECTLY. Use MarkForDeletion() if this monster needs to be marked. NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
private: private:
struct STRATEGY{ struct STRATEGY{
static std::string ERR; static std::string ERR;
@ -269,6 +276,7 @@ private:
static void GOBLIN_BOMB(Monster&m,float fElapsedTime,std::string strategy); static void GOBLIN_BOMB(Monster&m,float fElapsedTime,std::string strategy);
static void HAWK(Monster&m,float fElapsedTime,std::string strategy); static void HAWK(Monster&m,float fElapsedTime,std::string strategy);
static void STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy); static void STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy);
static void DONOTHING(Monster&m,float fElapsedTime,std::string strategy);
}; };
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame. bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player. bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.

@ -62,6 +62,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("Goblin Bomb",Monster::STRATEGY::GOBLIN_BOMB); STRATEGY_DATA.insert("Goblin Bomb",Monster::STRATEGY::GOBLIN_BOMB);
STRATEGY_DATA.insert("Hawk",Monster::STRATEGY::HAWK); STRATEGY_DATA.insert("Hawk",Monster::STRATEGY::HAWK);
STRATEGY_DATA.insert("Stone Elemental",Monster::STRATEGY::STONE_ELEMENTAL); STRATEGY_DATA.insert("Stone Elemental",Monster::STRATEGY::STONE_ELEMENTAL);
STRATEGY_DATA.insert("Do Nothing",Monster::STRATEGY::DONOTHING);
STRATEGY_DATA.SetInitialized(); STRATEGY_DATA.SetInitialized();
} }

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 9270 #define VERSION_BUILD 9271
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -725,4 +725,8 @@ MonsterStrategy
# Minimum Distance the Stone Elemental will always perform a dive # Minimum Distance the Stone Elemental will always perform a dive
Auto Dive Range = 1200 Auto Dive Range = 1200
} }
Do Nothing
{
}
} }

@ -786,17 +786,17 @@ Monsters
Invulnerable = True Invulnerable = True
MoveSpd = 0% MoveSpd = 0%
# Due to the Stone Elemental's base sprite size being 36x36, 220% is actually 146.666666667% size when factoring in a 50% larger sprite. # The Pillar is supposed to be 350 radius.
Size = 100% Size = 350%
Collision Radius = 59 Collision Radius = 8
Lifetime = 5s Lifetime = 5s
XP = 0 XP = 0
Strategy = Run Towards Strategy = Do Nothing
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 168,528 SheetFrameSize = 24,96
# Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST
4-Way Spritesheet = False 4-Way Spritesheet = False
@ -806,7 +806,7 @@ Monsters
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# Animations must be defined in the same order as they are in their sprite sheets # Animations must be defined in the same order as they are in their sprite sheets
# The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
IDLE = 1, 0.6, Repeat IDLE = 4, 0.4, OneShot
WALK = 1, 0.2, Repeat WALK = 1, 0.2, Repeat
STAND BEHIND ME = 1, 0.2, OneShot STAND BEHIND ME = 1, 0.2, OneShot
DEATH = 1, 0.15, OneShot DEATH = 1, 0.15, OneShot

@ -45,32 +45,34 @@ Credits
LINE[42]="ERA OF FANTASY - GRASSLANDS" LINE[42]="ERA OF FANTASY - GRASSLANDS"
LINE[43]="X: @Namatnieks" LINE[43]="X: @Namatnieks"
LINE[44]=" " LINE[44]=" "
LINE[45]="*** Minifantasy - Tiny Overworld v1.0 ***" LINE[45]="Fantastic Pillar by InThePixel"
LINE[46]="Minifantasy is an original idea by Krishna Palacio" LINE[46]=" "
LINE[47]=" " LINE[47]="*** Minifantasy - Tiny Overworld v1.0 ***"
LINE[48]="Public Domain Font Authors" LINE[48]="Minifantasy is an original idea by Krishna Palacio"
LINE[49]="c64esque by andraaspar" LINE[49]=" "
LINE[50]="Habbo by Omni" LINE[50]="Public Domain Font Authors"
LINE[51]="Unknown by Anonymous" LINE[51]="c64esque by andraaspar"
LINE[52]=" " LINE[52]="Habbo by Omni"
LINE[53]="Nb Pixel Font Bundle" LINE[53]="Unknown by Anonymous"
LINE[54]="Nb Pixel Font Bundle 2" LINE[54]=" "
LINE[55]=" " LINE[55]="Nb Pixel Font Bundle"
LINE[56]=" " LINE[56]="Nb Pixel Font Bundle 2"
LINE[57]="Game License" LINE[57]=" "
LINE[58]="~~~~~~~~~~~~~~~~" LINE[58]=" "
LINE[59]="License (OLC-3)" LINE[59]="Game License"
LINE[60]="~~~~~~~~~~~~~~~" LINE[60]="~~~~~~~~~~~~~~~~"
LINE[61]=" " LINE[61]="License (OLC-3)"
LINE[62]="Copyright ` 2024 Sig Productions <niconiconii@lestoria.net>" LINE[62]="~~~~~~~~~~~~~~~"
LINE[63]=" " LINE[63]=" "
LINE[64]="Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:" LINE[64]="Copyright ` 2024 Sig Productions <niconiconii@lestoria.net>"
LINE[65]=" " LINE[65]=" "
LINE[66]="1. Redistributions or derivations of source code must retain the above copyright notice, this list of conditions and the following disclaimer." LINE[66]="Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:"
LINE[67]=" " LINE[67]=" "
LINE[68]="2. Redistributions or derivative works in binary form must reproduce the above copyright notice. This list of conditions and the following disclaimer must be reproduced in the documentation and/or other materials provided with the distribution." LINE[68]="1. Redistributions or derivations of source code must retain the above copyright notice, this list of conditions and the following disclaimer."
LINE[69]=" " LINE[69]=" "
LINE[70]="3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission." LINE[70]="2. Redistributions or derivative works in binary form must reproduce the above copyright notice. This list of conditions and the following disclaimer must be reproduced in the documentation and/or other materials provided with the distribution."
LINE[71]=" " LINE[71]=" "
LINE[72]="THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." LINE[72]="3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission."
LINE[73]=" "
LINE[74]="THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
} }
Loading…
Cancel
Save