Changeset 11192 for code/branches
- Timestamp:
- May 19, 2016, 5:50:36 PM (9 years ago)
- Location:
- code/branches/tgidronFS16
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/tgidronFS16/data/levels/Hover.oxw
r11184 r11192 25 25 MAZE_SIZE = MAZE_NUM_CELLS*MAZE_CELL_SIZE 26 26 ?> 27 <!--28 <Template name=mediumdamagehoverpickupRepresentation>29 <PickupRepresentation>30 <spawner-representation>31 <StaticEntity>32 <attached>33 <Billboard position="0,0,0" colour="0.95,0.10,0.05" material="Sphere2" scale=0.1 >34 <attached>35 <Billboard position="0,0,0" colour="0.70,0.10,0.10" material="Damage" scale=0.5 />36 </attached>37 </Billboard>38 </attached>39 </StaticEntity>40 </spawner-representation>41 </PickupRepresentation>42 </Template>43 44 <Template name=damagehover baseclass=DamageBoostPickup>45 <DamageBoostPickup46 representation = "mediumdamagehoverpickup"47 duration = 10.048 damageMultiplier = 5.049 activationType = "immediate"50 durationType = "continuous"51 />52 </Template> -->53 27 54 28 <!-- Shrink Pickup Representation --> … … 59 33 <StaticEntity> 60 34 <attached> 61 <Billboard position="0, 50,0" colour="1.0,0.55,1.0" material="Sphere2" scale=1>35 <Billboard position="0,0,0" colour="1.0,0.55,1.0" material="Sphere2" scale=0.5> 62 36 <attached> 63 37 <Billboard position="0,0,0" colour="1.0,0.55,1.0" material="Shrink" scale=0.35 /> … … 75 49 representation = "smallshrinkpickup" 76 50 duration = 10.0 77 shrinkFactor = 2 .551 shrinkFactor = 2 78 52 activaionType = "immediate" 79 53 durationType = "continuous" … … 88 62 <StaticEntity> 89 63 <attached> 90 <Billboard position="0, 50,0" colour="0.99,0.96,0.52" material="Sphere2" scale=1>64 <Billboard position="0,0,0" colour="0.99,0.96,0.52" material="Sphere2" scale=0.5> 91 65 <attached> 92 66 <Billboard position="0,0,0" colour="0.98,0.94,0.22" material="3arrowsup" scale=0.7 /> … … 104 78 duration = 10.0 105 79 speedAdd = 0.0 106 SpeedMultiply = 5 0.080 SpeedMultiply = 5.0 107 81 activationType = "immediate" 108 82 durationType = "continuous" … … 117 91 <StaticEntity> 118 92 <attached> 119 <Billboard position="0, 50,0" colour="0.6,0.⁰,0.8" material="Sphere2" scale=1>93 <Billboard position="0,0,0" colour="0.6,0.⁰,0.8" material="Sphere2" scale=0.5> 120 94 <attached> 121 95 <Billboard position="0,0,0" colour="0.6,0.⁰,0.8" material="Asterisk" scale=0.65 /> … … 135 109 136 110 <Template name=obstacle baseclass=Pawn> 137 <Pawn team=1 health=30 position="0,100,0" direction="0,-1,0" collisionType=dynamic mass=100000 name=box RVName = "Box 4" >111 <Pawn team=1 health=30 position="0,100,0" direction="0,-1,0" collisionType=dynamic mass=10000000000000 name=box RVName = "Box 4" > 138 112 <attached> 139 <Model position="0, 50,0" mesh="crate.mesh" scale3D="15,15,15" />113 <Model position="0,0,0" mesh="crate.mesh" scale3D="15,15,15" /> 140 114 </attached> 141 115 <collisionShapes> … … 145 119 </Template> 146 120 121 <!-- Ground Template --> 122 123 <Template name=ground baseclass=StaticEntity> 124 <StaticEntity position="0,0,0" direction="0,0,0" collisionType=static mass=100000000 friction=0.01 > 125 <attached> 126 <Model position="0,0,0" mesh="CubeGround.mesh" scale3D="300,20,300" /> 127 </attached> 128 <collisionShapes> 129 <BoxCollisionShape position="0,0,0" halfExtents="300,10,300" /> 130 </collisionShapes> 131 </StaticEntity> 132 </Template> 147 133 148 134 <Level … … 156 142 <?lua include("includes/notifications.oxi") ?> 157 143 158 159 <?lua160 for i = 1, 10, 1 do161 for j = 1,10 ,1 do162 ?>163 164 <StaticEntity position="0,0,0" collisionType="static">165 <attached>166 <Model167 position="<?lua print(MAZE_CELL_SIZE*i)?>, -16, <?lua print(MAZE_CELL_SIZE*j)?>"168 scale3D="<?lua print(MAZE_CELL_SIZE*i)?>, 16, <?lua print(MAZE_CELL_SIZE*j)?>"169 mesh="CubeGround.mesh"170 />171 </attached>172 <collisionShapes>173 <BoxCollisionShape174 position="<?lua print(MAZE_CELL_SIZE*i)?>, <?lua print(MAZE_CELL_HEIGHT+1)?>, <?lua print(MAZE_CELL_SIZE*j)?>"175 halfExtents="<?lua print(MAZE_CELL_SIZE*i)?>,1,<?lua print(MAZE_CELL_SIZE*j)?>"176 />177 <BoxCollisionShape178 position="<?lua print(MAZE_CELL_SIZE*i)?>,-1,<?lua print(MAZE_CELL_SIZE*j)?>"179 halfExtents="<?lua print(MAZE_CELL_SIZE*i)?>,1,<?lua print(MAZE_CELL_SIZE*j)?>"180 />181 </collisionShapes>182 183 <?lua184 end185 end186 ?>187 188 </StaticEntity>189 190 144 <Scene 191 145 ambientlight = "0.8, 0.8, 0.8" … … 217 171 inventoryRepresentation = "SmallShrink" 218 172 /> 219 <!--220 <PickupRepresentation221 name = "damagehover"222 pickupName = "Medium Damage Hover Pickup"223 pickupDescription = "Multiplies the ship damage with 5."224 spawnerTemplate = "mediumdamagehoverpickupRepresentation"225 inventoryRepresentation = "MediumDamageHover"226 /> -->227 173 228 174 <StaticEntity position="0,0,0" collisionType="static"> … … 239 185 pickuptemplateshrink=smallshrinkpickup 240 186 pickuprepresentationtemplateshrink=smallshrinkpickupRepresentation 187 groundtemplate=ground 241 188 /> 242 </attached> 243 189 190 </attached> 191 244 192 </StaticEntity> 245 193 … … 262 210 </Scene> 263 211 </Level> 264 265 266 267 <!--<<Model268 position="<?lua print(MAZE_SIZE/2)?>,-16,<?lua print(MAZE_SIZE/2)?>"269 scale3D="<?lua print(MAZE_SIZE/2)?>,16,<?lua print(MAZE_SIZE/2)?>"270 mesh="ss_wall.mesh"271 />272 </attached>273 274 <collisionShapes>275 <BoxCollisionShape276 position="<?lua print(MAZE_SIZE/2)?>,<?lua print(MAZE_CELL_HEIGHT+1)?>,<?lua print(MAZE_SIZE/2)?>"277 halfExtents="<?lua print(MAZE_SIZE/2)?>,1,<?lua print(MAZE_SIZE/2)?>"278 />279 <BoxCollisionShape280 position="<?lua print(MAZE_SIZE/2)?>,-1,<?lua print(MAZE_SIZE/2)?>"281 halfExtents="<?lua print(MAZE_SIZE/2)?>,1,<?lua print(MAZE_SIZE/2)?>"282 />283 </collisionShapes> --> -
code/branches/tgidronFS16/data/levels/includes/weaponSettingsHover.oxi
r11184 r11192 14 14 </links> 15 15 <Weapon> 16 <HsW01 mode=0 munitionpershot=0 delay=0.125 damage=9.3 material="Flares/point_lensflare" muzzleoffset=" 1, 1,-18" projectileMesh="LaserBeam2.mesh" />16 <HsW01 mode=0 munitionpershot=0 delay=0.125 speed=2000.0f damage=9.3 material="Flares/point_lensflare" muzzleoffset=" 1, 1,-50 " projectileMesh="LaserBeam2.mesh" /> 17 17 </Weapon> 18 18 <Weapon> 19 < EnergyDrink mode=0 munitionpershot=0 delay=0 damage=9.3 material="Flares/point_lensflare" muzzleoffset=" 0.8, 1, -18.0" projectileMesh="LaserBeam2.mesh" />19 <HsW01 mode=0 munitionpershot=0 delay=0.125 speed=2000.0f damage=9.3 material="Flares/point_lensflare" muzzleoffset=" 0.8, 1,-50" projectileMesh="LaserBeam2.mesh" /> 20 20 </Weapon> 21 21 </WeaponPack> … … 27 27 </weaponpacks> 28 28 <munition> 29 <LaserMunition initialmagazines=1 maxmagazines=1 munitionpermagazine=10/> 30 <FusionMunition initialmagazines=1 maxmagazines=1 munitionpermagazine=10/> 29 <LaserMunition initialmagazines=2 maxmagazines=2 munitionpermagazine=20/> 31 30 </munition> -
code/branches/tgidronFS16/data/levels/templates/spaceshipHover.oxt
r11184 r11192 22 22 rotationThrust = 45 23 23 24 jumpBoost = 23024 jumpBoost = 450 25 25 26 26 lift = 1; … … 33 33 34 34 collisionType = "dynamic" 35 mass = 100000 35 mass = 1000000 36 36 linearDamping = 0.2 37 37 angularDamping = 0.9999999 … … 47 47 </attached> 48 48 <collisionShapes> 49 <BoxCollisionShape position="0,-12, 42" halfExtents="4 2, 24 ,180" />49 <BoxCollisionShape position="0,-12, 42" halfExtents="49, 24 ,180" /> 50 50 </collisionShapes> 51 51 <explosion> 52 52 <ExplosionPart minspeed=0 maxspeed=0 effect1="orxonox/explosion_flash2" effect2="orxonox/explosion_flame2" /> 53 <ExplosionPart minspeed=0 maxspeed=0 effect1="orxonox/explosion_shockwave2" effect2="orxonox/explosion_sparks2" scale= 2 />53 <ExplosionPart minspeed=0 maxspeed=0 effect1="orxonox/explosion_shockwave2" effect2="orxonox/explosion_sparks2" scale=12 /> 54 54 <ExplosionPart minspeed=0 maxspeed=0 effect1="orxonox/explosion_streak2" effect2="orxonox/explosion_afterglow" /> 55 55 … … 81 81 speedfront = 1400 82 82 speedback = 800 83 speedleftright = 60084 speedupdown = 60083 speedleftright = 700 84 speedupdown = 700 85 85 86 86 accelerationfront = 1000 87 87 accelerationbrake = 1000 88 88 accelerationback = 250 89 accelerationleftright = 25089 accelerationleftright = 350 90 90 accelerationupdown = 125 91 91 > -
code/branches/tgidronFS16/data/overlays/HoverHUD.oxo
r11177 r11192 45 45 </HUDHealthBar> 46 46 47 48 <HUDNavigation49 name = "Navigation"50 correctaspect = true51 font = "Monofur"52 textsize = 0.0253 navMarkerSize = 0.0354 aimMarkerSize = 0.0255 />56 47 57 48 -
code/branches/tgidronFS16/src/modules/hover/Hover.cc
r11184 r11192 64 64 cellHeight = 0; 65 65 66 bShowLevel = false; 67 66 68 totFlags = 0; 67 69 … … 80 82 cellSize = this->origin_->getCellSize(); 81 83 cellHeight = this->origin_->getCellHeight(); 84 85 /* 86 bool occupiedCells[numCells][numCells]; 87 88 for(int i = 0; i < numCells; i++) 89 { 90 for(int j = 0; j < numCells; j++) 91 { 92 occupiedCells[i][j] = false; 93 } 94 } 95 occupiedCells[0][0] = true; 96 */ 82 97 83 98 MazeGenerator generator(numCells); … … 93 108 (new HoverWall(origin_->getContext()))->init(i+1, 0, cellSize, cellHeight, 2); 94 109 (new HoverWall(origin_->getContext()))->init(i+1, numCells, cellSize, cellHeight, 2); 110 } 111 112 113 //Ground 114 for(int i = 0; i<numCells; i++){ 115 for(int j = 0; j<numCells; j++){ 116 StaticEntity* groundCell = new StaticEntity(origin_->getContext()); 117 118 groundCell->addTemplate(origin_->getGroundTemplate()); 119 groundCell->setPosition(get3dCoordinates(i,j,-60)); 120 } 121 95 122 } 96 123 … … 112 139 } 113 140 114 //Generate 5 flags randomly (test only 1 flag) 141 createFlags(); 142 143 //Generate 3 PickupSpawners randomly (destroy hover pickup) 144 for (int i = 0; i<3; i++) 145 { 146 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 147 148 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 0.0f)); 149 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplate()); 150 pickupSpawner->setMaxSpawnedItems(3); 151 pickupSpawner->setRespawnTime(30); 152 pickupSpawner->setTriggerDistance(40); 153 // Add pickup spawner to the pickup spawner list 154 pickupSpawners_.push_back(pickupSpawner); 155 } 156 157 //Generate 3 PickupSpawners randomly (speed pickup) 158 for (int i = 0; i<3; i++) 159 { 160 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 161 162 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 0.0f)); 163 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplateSpeed()); 164 pickupSpawner->setMaxSpawnedItems(3); 165 pickupSpawner->setRespawnTime(30); 166 pickupSpawner->setTriggerDistance(40); 167 // Add pickup spawner to the pickup spawner list 168 pickupSpawners_.push_back(pickupSpawner); 169 } 170 171 //Generate 3 PickupSpawners randomly (shrink pickup) 172 for (int i = 0; i<3; i++) 173 { 174 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 175 176 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 0.0f)); 177 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplateShrink()); 178 pickupSpawner->setMaxSpawnedItems(3); 179 pickupSpawner->setRespawnTime(30); 180 pickupSpawner->setTriggerDistance(40); 181 // Add pickup spawner to the pickup spawner list 182 pickupSpawners_.push_back(pickupSpawner); 183 } 184 185 //***************************************************************************** 186 187 //Generate destroyable crates randomly on field 188 189 for (int i = 0; i<10; i++){ 190 191 Pawn* crate = new Pawn(origin_->getContext()); 192 193 crate->addTemplate(origin_->getObstacleTemplate()); 194 crate->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 43.0f)); 195 196 197 } 198 199 200 201 202 //If no lives are left, end game 203 if(lives <= 0) 204 { 205 GSLevel::startMainMenu(); 206 } 207 // Debug 208 orxout() << this->origin_->getPickupTemplate() << endl; 209 orxout() << this->origin_->getPickupRepresentationTemplate() << endl; 210 211 212 orxout() << this->origin_->getPickupTemplateSpeed() << endl; 213 orxout() << this->origin_->getPickupRepresentationTemplateSpeed() << endl; 214 215 orxout() << this->origin_->getObstacleTemplate() << endl; 216 //orxout() << crate->getPosition() << endl; 217 } 218 } 219 220 221 // Start new level 222 void Hover::createFlags() 223 { 224 //Generate 5 flags randomly (test only 1 flag) 225 226 /* do 227 { 228 int i = 0; 229 230 HoverFlag* flag = new HoverFlag(origin_->getContext()); 231 int x = rand()%numCells; 232 int y = rand()%numCells; 233 flag->init(x, y, cellSize); 234 flags_.push_back(flag); 235 236 occupiedCells[x][y] = true; 237 238 i++; 239 240 }while( i<5 || occupiedCells[x][y] == true); 241 */ 242 115 243 for ( int i = 0; i < 5; i++ ) 116 244 { … … 118 246 flag->init(rand()%numCells, rand()%numCells, cellSize); 119 247 flags_.push_back(flag); 120 } 248 121 249 122 250 123 //Generate 3 PickupSpawners randomly (destroy hover pickup) 124 for (int i = 0; i<3; i++) 125 { 126 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 127 128 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 10.0f)); 129 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplate()); 130 pickupSpawner->setMaxSpawnedItems(3); 131 pickupSpawner->setRespawnTime(30); 132 pickupSpawner->setTriggerDistance(5); 133 // Add pickup spawner to the pickup spawner list 134 pickupSpawners_.push_back(pickupSpawner); 135 } 136 137 //Generate 3 PickupSpawners randomly (speed pickup) 138 for (int i = 0; i<3; i++) 139 { 140 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 141 142 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 10.0f)); 143 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplateSpeed()); 144 pickupSpawner->setMaxSpawnedItems(3); 145 pickupSpawner->setRespawnTime(30); 146 pickupSpawner->setTriggerDistance(5); 147 // Add pickup spawner to the pickup spawner list 148 pickupSpawners_.push_back(pickupSpawner); 149 } 150 151 //Generate 3 PickupSpawners randomly (shrink pickup) 152 for (int i = 0; i<3; i++) 153 { 154 PickupSpawner* pickupSpawner = new PickupSpawner(origin_->getContext()); 155 156 pickupSpawner->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 10.0f)); 157 pickupSpawner->setPickupTemplateName(origin_->getPickupTemplateShrink()); 158 pickupSpawner->setMaxSpawnedItems(3); 159 pickupSpawner->setRespawnTime(30); 160 pickupSpawner->setTriggerDistance(5); 161 // Add pickup spawner to the pickup spawner list 162 pickupSpawners_.push_back(pickupSpawner); 163 } 164 165 //***************************************************************************** 166 167 //Generate a destroyable crate randomly on field 168 169 Pawn* crate = new Pawn(origin_->getContext()); 170 171 172 crate->addTemplate(origin_->getObstacleTemplate()); 173 crate->setPosition(get3dCoordinates(rand()%numCells, rand()%numCells, 10.0f)); 174 //ate->setInitialHealth(100.0f); 175 176 177 178 179 //If no lives are left, end game 180 if(lives <= 0) 181 { 182 GSLevel::startMainMenu(); 183 } 184 // Debug 185 orxout() << this->origin_->getPickupTemplate() << endl; 186 orxout() << this->origin_->getPickupRepresentationTemplate() << endl; 187 188 orxout() << this->origin_->getPickupTemplateSpeed() << endl; 189 orxout() << this->origin_->getPickupRepresentationTemplateSpeed() << endl; 190 191 orxout() << this->origin_->getObstacleTemplate() << endl; 192 orxout() << crate->getPosition() << endl; 193 } 194 } 195 196 197 // Start new level 198 void Hover::newLevel() 199 { 200 //Generate 5 flags randomly (test only 1 flag) 201 for ( int i = 0; i < 5; i++ ) 202 { 203 HoverFlag* flag = new HoverFlag(origin_->getContext()); 204 flag->init(rand()%numCells, rand()%numCells, cellSize); 205 flags_.push_back(flag); 251 if(flags_[i]->getPosition() == get3dCoordinates(0,0,-60)) 252 { 253 flags_[i]->destroyLater(); 254 flags_.erase(flags_.begin()+i); 255 } 206 256 } 207 257 … … 245 295 lives++; 246 296 } 247 newLevel(); 297 createFlags(); 298 toggleShowLevel(); 299 showLevelTimer.setTimer(1.0f, false, createExecutor(createFunctor(&Hover::toggleShowLevel, this))); 248 300 249 301 } -
code/branches/tgidronFS16/src/modules/hover/Hover.h
r11182 r11192 58 58 59 59 void start(); 60 void newLevel();60 void createFlags(); 61 61 void levelUp(); 62 62 void endLevel(); … … 77 77 { return this->level; } 78 78 79 bool bShowLevel; 80 79 81 private: 80 82 … … 94 96 95 97 std::vector<PickupSpawner*> pickupSpawners_; 96 98 99 void toggleShowLevel(){bShowLevel = !bShowLevel;} 100 101 Timer showLevelTimer; 97 102 }; 98 103 } -
code/branches/tgidronFS16/src/modules/hover/HoverOrigin.cc
r11184 r11192 73 73 XMLPortParam(HoverOrigin, "pickuptemplateshrink", setPickupTemplateShrink, getPickupTemplateShrink, xmlelement, mode); 74 74 XMLPortParam(HoverOrigin, "pickuprepresentationtemplateshrink", setPickupRepresentationTemplateShrink, getPickupRepresentationTemplateShrink, xmlelement, mode); 75 XMLPortParam(HoverOrigin, "groundtemplate", setGroundTemplate, getGroundTemplate, xmlelement, mode); 75 76 } 76 77 -
code/branches/tgidronFS16/src/modules/hover/HoverOrigin.h
r11182 r11192 110 110 { return this->obstacleTemplate_; } 111 111 112 //get and set for ground template 113 114 inline void setGroundTemplate(std::string groundTemplate) 115 { this->groundTemplate_ = groundTemplate; } 116 inline std::string getGroundTemplate() const 117 { return this->groundTemplate_; } 118 112 119 private: 113 120 void checkGametype(); … … 132 139 //Template for crate obstacle 133 140 std::string obstacleTemplate_; 141 142 //Template for ground cell 143 std::string groundTemplate_; 134 144 }; 135 145 } -
code/branches/tgidronFS16/src/modules/hover/TFlagsLivesLevelHUD.cc
r11177 r11192 85 85 this->setColour(ColourValue(1, 1, 1, 1)); 86 86 this->setCaption(level); 87 87 88 } 88 89 90 if(this->hoverGame_->bShowLevel) 91 { 92 setTextSize(0.2); 93 setPosition(Vector2(0.3, 0.55)); 94 std::stringstream sstm; 95 sstm << "Level " << level; 96 this->setCaption(sstm.str()); 97 } 89 98 } 90 99 -
code/branches/tgidronFS16/src/modules/hover/TFlagsLivesLevelHUD.h
r11177 r11192 85 85 { return this->totLevel_; } 86 86 87 87 88 private: 88 89 Hover* hoverGame_; -
code/branches/tgidronFS16/src/modules/invader/Invader.cc
r11083 r11192 71 71 // spawn enemy every 3.5 seconds 72 72 enemySpawnTimer.setTimer(3.5f, true, createExecutor(createFunctor(&Invader::spawnEnemy, this))); 73 comboTimer.setTimer(3.0f, true, createExecutor(createFunctor(&Invader::comboControll, this)));73 comboTimer.setTimer(3.0f, false, createExecutor(createFunctor(&Invader::comboControll, this))); 74 74 this->setHUDTemplate("InvaderHUD"); 75 75 } -
code/branches/tgidronFS16/src/modules/weapons/weaponmodes/HsW01.cc
r11108 r11192 85 85 XMLPortParam(HsW01, "projectileMesh", setMesh, getMesh, xmlelement, mode); 86 86 XMLPortParam(HsW01, "sound", setSound, getSound, xmlelement, mode); 87 XMLPortParam(HsW01, "speed", setSpeed, getSpeed, xmlelement, mode); 87 88 } 88 89 -
code/branches/tgidronFS16/src/modules/weapons/weaponmodes/HsW01.h
r11099 r11192 112 112 void muzzleflash(); 113 113 114 /** 115 @brief Set the firing speed. 116 @param speed The speed of the shot 117 */ 118 119 void setSpeed(const float speed) 120 { this->speed_ = speed; } 121 122 /** 123 @brief Get the firing speed. 124 @return Returns the speed of the shot 125 */ 126 127 const float getSpeed() const 128 { return this->speed_; } 129 114 130 std::string material_; //!< The material. 115 131 std::string mesh_; //!< The mesh.
Note: See TracChangeset
for help on using the changeset viewer.