[Scummvm-git-logs] scummvm master -> 0c77e51249fca8bdf63981a126300fdf0f9fb771

bluegr noreply at scummvm.org
Wed Aug 19 22:34:33 UTC 2026


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
5c6346d8bb NANCY: NANCY14: Remove now obsolete function from HangmanPuzzle
0c77e51249 NANCY: NANCY14: Implement AdjustPuzzle


Commit: 5c6346d8bb878d7b04e56df6c69b0aa4a1ee4b4b
    https://github.com/scummvm/scummvm/commit/5c6346d8bb878d7b04e56df6c69b0aa4a1ee4b4b
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-08-20T01:27:52+03:00

Commit Message:
NANCY: NANCY14: Remove now obsolete function from HangmanPuzzle

This was used during development, and is no longer needed

Changed paths:
    engines/nancy/action/puzzle/hangmanpuzzle.cpp
    engines/nancy/action/puzzle/hangmanpuzzle.h


diff --git a/engines/nancy/action/puzzle/hangmanpuzzle.cpp b/engines/nancy/action/puzzle/hangmanpuzzle.cpp
index 1bec805cf24..dada33264a1 100644
--- a/engines/nancy/action/puzzle/hangmanpuzzle.cpp
+++ b/engines/nancy/action/puzzle/hangmanpuzzle.cpp
@@ -201,23 +201,6 @@ Common::Rect HangmanPuzzle::glyphForLetter(char letter) const {
 	return Common::Rect();
 }
 
-// Blits srcRect from src at destPos, clipping srcRect to the source image so an
-// out-of-bounds sprite rect (or an image that failed to load) can't read past
-// the surface.
-void HangmanPuzzle::safeBlit(const Graphics::ManagedSurface &src, const Common::Rect &srcRect, const Common::Point &destPos) {
-	if (src.w == 0 || src.h == 0 || srcRect.isEmpty()) {
-		return;
-	}
-
-	Common::Rect clipped = srcRect.findIntersectingRect(Common::Rect(src.w, src.h));
-	if (clipped.isEmpty()) {
-		return;
-	}
-
-	Common::Point dst(destPos.x + (clipped.left - srcRect.left), destPos.y + (clipped.top - srcRect.top));
-	_drawSurface.blitFrom(src, clipped, dst);
-}
-
 void HangmanPuzzle::redraw() {
 	_drawSurface.clear(g_nancy->_graphics->getTransColor());
 
@@ -228,21 +211,21 @@ void HangmanPuzzle::redraw() {
 	// the puzzle sheet) onto the tile's alphabet position (1st tile rect).
 	for (const LetterTile &tile : _letters) {
 		if (tile.used) {
-			safeBlit(_puzzleImage, tile.hoverRect, Common::Point(tile.idleRect.left, tile.idleRect.top));
+			_drawSurface.blitFrom(_puzzleImage, tile.hoverRect, Common::Point(tile.idleRect.left, tile.idleRect.top));
 		}
 	}
 
 	// Guessed-letters row: each played letter's glyph (from the letters sheet)
 	// at its slot in the row.
 	for (uint i = 0; i < _guessed.size() && i < _guessedRowRects.size(); ++i) {
-		safeBlit(_lettersImage, glyphForLetter(_guessed[i]),
+		_drawSurface.blitFrom(_lettersImage, glyphForLetter(_guessed[i]),
 			Common::Point(_guessedRowRects[i].left, _guessedRowRects[i].top));
 	}
 
 	// Revealed word letters in their blanks.
 	for (uint i = 0; i < _revealed.size() && i < _letterSlotRects.size(); ++i) {
 		if (_revealed[i]) {
-			safeBlit(_lettersImage, glyphForLetter(_word[i]),
+			_drawSurface.blitFrom(_lettersImage, glyphForLetter(_word[i]),
 				Common::Point(_letterSlotRects[i].left, _letterSlotRects[i].top));
 		}
 	}
@@ -250,7 +233,7 @@ void HangmanPuzzle::redraw() {
 	// The hang figure: the current cumulative stage sprite (from the sheet's
 	// stage strip) drawn at the board position.
 	if (_wrongCount > 0 && _wrongCount <= (int)_hangPieceRects.size()) {
-		safeBlit(_puzzleImage, _hangPieceRects[_wrongCount - 1],
+		_drawSurface.blitFrom(_puzzleImage, _hangPieceRects[_wrongCount - 1],
 			Common::Point(_boardRect.left, _boardRect.top));
 	}
 
diff --git a/engines/nancy/action/puzzle/hangmanpuzzle.h b/engines/nancy/action/puzzle/hangmanpuzzle.h
index 3d8992cdbd1..34632972fb8 100644
--- a/engines/nancy/action/puzzle/hangmanpuzzle.h
+++ b/engines/nancy/action/puzzle/hangmanpuzzle.h
@@ -80,7 +80,6 @@ protected:
 	Common::Rect glyphForLetter(char letter) const;	// glyph rect of the tile for this letter, or empty
 	int tileAtCursor(const Common::Point &mousePos) const;
 	void commitGuess(uint tileIndex);
-	void safeBlit(const Graphics::ManagedSurface &src, const Common::Rect &srcRect, const Common::Point &destPos);
 	void redraw();
 	void applyOutcome(const SceneOutcome &outcome);
 


Commit: 0c77e51249fca8bdf63981a126300fdf0f9fb771
    https://github.com/scummvm/scummvm/commit/0c77e51249fca8bdf63981a126300fdf0f9fb771
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-08-20T01:30:40+03:00

Commit Message:
NANCY: NANCY14: Implement AdjustPuzzle

This is a simple puzzle, used when calibrating the plotter

Changed paths:
  A engines/nancy/action/puzzle/adjustpuzzle.cpp
  A engines/nancy/action/puzzle/adjustpuzzle.h
    engines/nancy/action/arfactory.cpp
    engines/nancy/module.mk


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 0c414aeeb60..ab2a338fa10 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -32,6 +32,7 @@
 #include "engines/nancy/action/secondaryvideo.h"
 #include "engines/nancy/action/secondarymovie.h"
 
+#include "engines/nancy/action/puzzle/adjustpuzzle.h"
 #include "engines/nancy/action/puzzle/angletosspuzzle.h"
 #include "engines/nancy/action/puzzle/arcadepuzzle.h"
 #include "engines/nancy/action/puzzle/assemblypuzzle.h"
@@ -509,9 +510,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	// -- Nancy14 new puzzles (types 177-182) --
 	case 177:
 		return new HangmanPuzzle();
-	case 178:	// AdjustPuzzle
-		// TODO: not yet implemented
-		return nullptr;
+	case 178:
+		return new AdjustPuzzle();
 	case 179:	// MeterPuzzle
 		// TODO: not yet implemented
 		return nullptr;
diff --git a/engines/nancy/action/puzzle/adjustpuzzle.cpp b/engines/nancy/action/puzzle/adjustpuzzle.cpp
new file mode 100644
index 00000000000..7280b91cb50
--- /dev/null
+++ b/engines/nancy/action/puzzle/adjustpuzzle.cpp
@@ -0,0 +1,308 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/util.h"
+
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/cursor.h"
+#include "engines/nancy/graphics.h"
+#include "engines/nancy/input.h"
+#include "engines/nancy/resource.h"
+#include "engines/nancy/util.h"
+
+#include "engines/nancy/action/puzzle/adjustpuzzle.h"
+
+#include "engines/nancy/state/scene.h"
+
+namespace Nancy {
+namespace Action {
+
+void AdjustPuzzle::readData(Common::SeekableReadStream &stream) {
+	readFilename(stream, _imageName);		// 0x1c0
+	_field3d = stream.readSint16LE();		// 0x3d
+
+	int16 numPieces = stream.readSint16LE();
+	_pieces.resize(numPieces);				// 0x3f
+	for (int16 i = 0; i < numPieces; ++i) {
+		Piece &piece = _pieces[i];
+		for (int j = 0; j < 4; ++j) {
+			readRect(stream, piece.rects[j]);
+		}
+		int16 numSubRects = stream.readSint16LE();
+		readRectArray(stream, piece.subRects, numSubRects);
+		piece.initialState = stream.readByte();
+		readRect(stream, piece.boundRect);
+	}
+
+	_pieceSound.readData(stream);			// 0x4f
+
+	readRect(stream, _rectA5);				// 0xa5
+	readRect(stream, _rectB5);				// 0xb5
+
+	_testSound.readData(stream);			// 0xc5
+
+	readFilename(stream, _adjustName);		// 0x11b
+	if (!_adjustName.empty()) {
+		_hasAdjustRect = true;
+		readRect(stream, _adjustRect);		// 0x11f
+		_adjustSound.readData(stream);		// 0x12f
+	}
+
+	_field18a = stream.readSint16LE();		// 0x18a
+
+	int16 numOverlays = stream.readSint16LE();
+	_overlayNames.resize(numOverlays);		// 0x18c
+	for (int16 i = 0; i < numOverlays; ++i) {
+		readFilename(stream, _overlayNames[i]);
+	}
+
+	int16 numRows = stream.readSint16LE();
+	_matrix.resize(numRows);				// 0x1b0
+	for (int16 i = 0; i < numRows; ++i) {
+		MatrixRow &row = _matrix[i];
+		row.cols.resize(numPieces);
+		for (int16 j = 0; j < numPieces; ++j) {
+			row.cols[j] = stream.readSint16LE();
+		}
+		row.result = stream.readByte();
+	}
+
+	_defaultResult = stream.readByte();		// 0x1c4
+	_perfectResult = stream.readByte();		// 0x1c5
+
+	Outcome *outcomes[] = { &_winScene, &_loseScene };
+	for (Outcome *outcome : outcomes) {
+		outcome->sceneID = stream.readSint16LE();
+		outcome->frameID = stream.readSint16LE();
+		outcome->flag.label = stream.readSint16LE();
+		outcome->flag.flag = stream.readByte();
+		outcome->sound.readData(stream);
+	}
+
+	// Trailing count-prefixed array of 23-byte give-up hotspots
+	// {Rect, uint16 cursorType, uint16 sceneID, int16 flagLabel, byte flagValue}.
+	// The exit always jumps to the scene's first frame.
+	int16 numExitZones = stream.readSint16LE();
+	for (int16 i = 0; i < numExitZones; ++i) {
+		Common::Rect r;
+		readRect(stream, r);
+		uint16 cursorType = stream.readUint16LE();
+		uint16 sceneID = stream.readUint16LE();
+		int16 flagLabel = stream.readSint16LE();
+		byte flagValue = stream.readByte();
+
+		if (i == 0) {
+			_exitHotspot = r;
+			_exitCursorType = cursorType;
+			_exitScene.sceneID = sceneID;
+			_exitScene.frameID = 0;
+			_exitFlag.label = flagLabel;
+			_exitFlag.flag = flagValue;
+		}
+	}
+}
+
+void AdjustPuzzle::init() {
+	Common::Rect vpBounds = NancySceneState.getViewport().getBounds();
+	_drawSurface.create(vpBounds.width(), vpBounds.height(),
+		g_nancy->_graphics->getInputPixelFormat());
+	_drawSurface.clear(g_nancy->_graphics->getTransColor());
+	setTransparent(true);
+	setVisible(true);
+	moveTo(vpBounds);
+
+	g_nancy->_resource->loadImage(_imageName, _image);
+	_image.setTransparentColor(_drawSurface.getTransparentColor());
+
+	_overlayImages.resize(_overlayNames.size());
+	for (uint i = 0; i < _overlayNames.size(); ++i) {
+		if (!_overlayNames[i].empty()) {
+			g_nancy->_resource->loadImage(_overlayNames[i], _overlayImages[i]);
+			_overlayImages[i].setTransparentColor(_drawSurface.getTransparentColor());
+		}
+	}
+
+	for (uint i = 0; i < _pieces.size(); ++i) {
+		_pieces[i].state = _pieces[i].initialState;
+	}
+
+	_resultIndex = 0;
+	_showResult = false;
+	_solved = false;
+	_lost = false;
+	_outcomeApplied = false;
+
+	redraw();
+}
+
+// Returns the piece whose +/- control is under the cursor, and sets delta to
+// +1 (increment) or -1 (decrement). Returns -1 if none. rects[1]/rects[3] are the
+// on-screen down/up arrow hotspots (rects[0]/rects[2] are the arrow sprites in the
+// image sheet).
+int AdjustPuzzle::pieceControlAtCursor(const Common::Point &mousePos, int &delta) const {
+	for (uint i = 0; i < _pieces.size(); ++i) {
+		const Piece &piece = _pieces[i];
+		if (!piece.rects[3].isEmpty() &&
+				NancySceneState.getViewport().convertViewportToScreen(piece.rects[3]).contains(mousePos)) {
+			delta = 1;	// up arrow
+			return (int)i;
+		}
+		if (!piece.rects[1].isEmpty() &&
+				NancySceneState.getViewport().convertViewportToScreen(piece.rects[1]).contains(mousePos)) {
+			delta = -1;	// down arrow
+			return (int)i;
+		}
+	}
+	return -1;
+}
+
+byte AdjustPuzzle::evaluateResult() const {
+	for (uint r = 0; r < _matrix.size(); ++r) {
+		const MatrixRow &row = _matrix[r];
+		bool match = true;
+		for (uint j = 0; j < _pieces.size() && j < row.cols.size(); ++j) {
+			if (row.cols[j] != _pieces[j].state) {
+				match = false;
+				break;
+			}
+		}
+		if (match) {
+			return row.result;
+		}
+	}
+	return _defaultResult;
+}
+
+void AdjustPuzzle::runTest() {
+	_resultIndex = evaluateResult();
+	_showResult = true;
+
+	if (_resultIndex == _perfectResult) {
+		_solved = true;
+	} else if (_loseScene.sceneID != kNoScene) {
+		// A lose scene is configured (kNoScene means "stay and let the player retry").
+		_lost = true;
+	}
+
+	redraw();
+}
+
+void AdjustPuzzle::redraw() {
+	_drawSurface.clear(g_nancy->_graphics->getTransColor());
+
+	if (_showResult && !_solved && _resultIndex >= 1 && (uint)(_resultIndex - 1) < _overlayImages.size()) {
+		// Result screen: the matched result overlay (a full-frame _TXT overlay).
+		const Graphics::ManagedSurface &overlay = _overlayImages[_resultIndex - 1];
+		_drawSurface.blitFrom(overlay, Common::Rect(overlay.w, overlay.h), Common::Point(0, 0));
+	} else {
+		// Levels run 1..5; level 1 is the default (from the scene background), and
+		// levels 2..5 show the sheet sprite subRects[level - 2] at the piece's
+		// on-screen bounding rect.
+		for (const Piece &piece : _pieces) {
+			int idx = piece.state - 2;
+			if (piece.state == 1 || idx < 0 || (uint)idx >= piece.subRects.size()) {
+				continue;
+			}
+			_drawSurface.blitFrom(_image, piece.subRects[idx],
+				Common::Point(piece.boundRect.left, piece.boundRect.top));
+		}
+	}
+
+	_needsRedraw = true;
+}
+
+void AdjustPuzzle::applyOutcome(const Outcome &outcome) {
+	SceneChangeDescription desc;
+	desc.sceneID = outcome.sceneID;
+	desc.frameID = outcome.frameID;
+	NancySceneState.changeScene(desc);
+	NancySceneState.setEventFlag(outcome.flag);
+}
+
+void AdjustPuzzle::handleInput(NancyInput &input) {
+	if (_state != kRun || _solved || _lost) {
+		return;
+	}
+
+	const bool click = (input.input & NancyInput::kLeftMouseButtonUp) != 0;
+
+	// Give-up hotspot: leave the puzzle.
+	if (!_exitHotspot.isEmpty() &&
+			NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
+		g_nancy->_cursor->setCursorType((CursorManager::CursorType)_exitCursorType, true);
+		if (click) {
+			_exitRequested = true;
+		}
+		input.eatMouseInput();
+		return;
+	}
+
+	int delta = 0;
+	int piece = pieceControlAtCursor(input.mousePos, delta);
+	if (piece >= 0) {
+		g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
+		if (click) {
+			// Levels run from 1 (default) up to 1 + the number of level sprites.
+			int maxState = 1 + (int)_pieces[piece].subRects.size();
+			_pieces[piece].state = CLIP<int>(_pieces[piece].state + delta, 1, maxState);
+			_showResult = false;
+			redraw();
+		}
+		input.eatMouseInput();
+		return;
+	}
+
+	// The "test" control: evaluate the current settings.
+	if (!_rectB5.isEmpty() &&
+			NancySceneState.getViewport().convertViewportToScreen(_rectB5).contains(input.mousePos)) {
+		g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
+		if (click) {
+			runTest();
+		}
+		input.eatMouseInput();
+	}
+}
+
+void AdjustPuzzle::execute() {
+	switch (_state) {
+	case kBegin:
+		init();
+		registerGraphics();
+		_state = kRun;
+		break;
+	case kRun:
+		if (_exitRequested) {
+			NancySceneState.setEventFlag(_exitFlag);
+			NancySceneState.changeScene(_exitScene);
+			break;
+		}
+		if ((_solved || _lost) && !_outcomeApplied) {
+			_outcomeApplied = true;
+			applyOutcome(_solved ? _winScene : _loseScene);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/puzzle/adjustpuzzle.h b/engines/nancy/action/puzzle/adjustpuzzle.h
new file mode 100644
index 00000000000..7a486f270b9
--- /dev/null
+++ b/engines/nancy/action/puzzle/adjustpuzzle.h
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NANCY_ACTION_ADJUSTPUZZLE_H
+#define NANCY_ACTION_ADJUSTPUZZLE_H
+
+#include "engines/nancy/commontypes.h"
+#include "engines/nancy/action/actionrecord.h"
+
+namespace Nancy {
+namespace Action {
+
+// Adjustment puzzle, new in Nancy14 (AR 178). Used for the plotter-repair
+// puzzle: several elements each have a state the player nudges up/down with
+// +/- controls. Testing the current settings matches the state tuple against a
+// table of combinations to pick a result; hitting the "perfect" result solves
+// the puzzle, any other shows a result overlay (Perfect-Vert / -Hor / -Mirror /
+// -Lite, ...) and fails.
+class AdjustPuzzle : public RenderActionRecord {
+public:
+	AdjustPuzzle() : RenderActionRecord(7) {}
+	virtual ~AdjustPuzzle() {}
+
+	void init() override;
+
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+	void handleInput(NancyInput &input) override;
+
+	bool isViewportRelative() const override { return true; }
+
+protected:
+	Common::String getRecordTypeName() const override { return "AdjustPuzzle"; }
+
+	// One adjustable element. rects[0]/rects[2] are the decrement/increment
+	// hotspots; subRects are the per-state display frames (blitted at boundRect).
+	struct Piece {
+		Common::Rect rects[4];
+		Common::Array<Common::Rect> subRects;
+		byte initialState = 0;
+		Common::Rect boundRect;
+		int state = 0;
+	};
+
+	// A row of the result table: the required state of each piece, plus the
+	// result index produced when the states match it.
+	struct MatrixRow {
+		Common::Array<int16> cols;
+		byte result = 0;
+	};
+
+	struct Outcome {
+		int16 sceneID = 0;
+		int16 frameID = 0;
+		FlagDescription flag;
+		RandomSoundBlock sound;
+	};
+
+	int pieceControlAtCursor(const Common::Point &mousePos, int &delta) const;
+	byte evaluateResult() const;
+	void runTest();
+	void redraw();
+	void applyOutcome(const Outcome &outcome);
+
+	// -- File data --
+	Common::Path _imageName;			// 0x1c0
+	int16 _field3d = 0;					// 0x3d
+	Common::Array<Piece> _pieces;		// 0x3f
+
+	Common::Rect _rectA5;				// 0xa5
+	Common::Rect _rectB5;				// 0xb5, "test"/go control
+
+	RandomSoundBlock _pieceSound;		// 0x4f, after the pieces
+	RandomSoundBlock _testSound;		// 0xc5
+
+	Common::Path _adjustName;			// 0x11b (plotter animation movie)
+	bool _hasAdjustRect = false;
+	Common::Rect _adjustRect;			// 0x11f
+	RandomSoundBlock _adjustSound;		// 0x12f (present only when _adjustName is set)
+
+	int16 _field18a = 0;						// 0x18a
+	Common::Array<Common::Path> _overlayNames;	// 0x18c, result overlays
+	Common::Array<MatrixRow> _matrix;			// 0x1b0
+
+	byte _defaultResult = 0;	// 0x1c4
+	byte _perfectResult = 0;	// 0x1c5
+	Outcome _winScene;			// 0x21c (field0), scene at 0x21e
+	Outcome _loseScene;			// 0x27d (field0), scene at 0x27f
+
+	// Give-up hotspot (count-prefixed 23-byte trailer): click to leave the puzzle.
+	Common::Rect _exitHotspot;
+	uint16 _exitCursorType = 0;
+	SceneChangeDescription _exitScene;
+	FlagDescription _exitFlag;
+
+	// -- Runtime state --
+	Graphics::ManagedSurface _image;
+	Common::Array<Graphics::ManagedSurface> _overlayImages;
+	byte _resultIndex = 0;
+	bool _showResult = false;
+	bool _solved = false;
+	bool _lost = false;
+	bool _outcomeApplied = false;
+	bool _exitRequested = false;
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_ADJUSTPUZZLE_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index fb5bee710f8..ba4c0173652 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -16,6 +16,7 @@ MODULE_OBJS = \
   action/overlay.o \
   action/secondarymovie.o \
   action/secondaryvideo.o \
+  action/puzzle/adjustpuzzle.o \
   action/puzzle/angletosspuzzle.o \
   action/puzzle/arcadepuzzle.o \
   action/puzzle/assemblypuzzle.o \




More information about the Scummvm-git-logs mailing list