Changeset 100
- Timestamp:
- Dec 26, 2014, 8:10:40 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Forms/UFormMain.lfm
r97 r100 5 5 Width = 775 6 6 Caption = 'xTactics' 7 ClientHeight = 59 27 ClientHeight = 595 8 8 ClientWidth = 775 9 9 Menu = MainMenu1 … … 18 18 object StatusBar1: TStatusBar 19 19 Left = 0 20 Height = 2 921 Top = 56 320 Height = 26 21 Top = 569 22 22 Width = 775 23 23 Panels = < … … 35 35 object ToolBar1: TToolBar 36 36 Left = 0 37 Height = 56 337 Height = 569 38 38 Top = 0 39 39 Width = 40 … … 73 73 object ToolButton6: TToolButton 74 74 Left = 1 75 Top = 1 7275 Top = 194 76 76 Action = AZoomIn 77 77 end 78 78 object ToolButton7: TToolButton 79 79 Left = 1 80 Top = 2 0480 Top = 226 81 81 Action = AZoomOut 82 82 end 83 83 object ToolButton8: TToolButton 84 84 Left = 1 85 Top = 2 3685 Top = 258 86 86 Action = AZoomAll 87 87 end 88 88 object ToolButton9: TToolButton 89 89 Left = 1 90 Height = 32 90 91 Top = 162 91 92 Width = 32 … … 94 95 object ToolButton10: TToolButton 95 96 Left = 1 96 Top = 268 97 Height = 32 98 Top = 290 97 99 Width = 32 98 100 Style = tbsSeparator … … 100 102 object ToolButton11: TToolButton 101 103 Left = 1 102 Top = 278104 Top = 322 103 105 Action = Core.AGameLoad 104 106 end 105 107 object ToolButton12: TToolButton 106 108 Left = 1 107 Top = 3 10109 Top = 354 108 110 Action = Core.AGameSave 109 111 end 110 112 object ToolButton13: TToolButton 111 113 Left = 1 112 Top = 3 42114 Top = 386 113 115 Action = Core.AExit 114 116 end … … 116 118 object PaintBox1: TPaintBox 117 119 Left = 40 118 Height = 56 3120 Height = 569 119 121 Top = 0 120 122 Width = 735 121 123 Align = alClient 122 124 OnMouseDown = PaintBox1MouseDown 125 OnMouseLeave = PaintBox1MouseLeave 123 126 OnMouseMove = PaintBox1MouseMove 124 127 OnMouseUp = PaintBox1MouseUp 125 OnMouseLeave = PaintBox1MouseLeave126 128 OnMouseWheelDown = PaintBox1MouseWheelDown 127 129 OnMouseWheelUp = PaintBox1MouseWheelUp -
trunk/Forms/UFormMain.pas
r97 r100 171 171 PaintBox1.Repaint; 172 172 StatusBar1.Panels[1].Text := IntToStr(Trunc(DrawDuration / OneMillisecond)) + ' / ' + 173 IntToStr(Trunc(TimerPeriod / OneMillisecond)) + ' ms'; 173 IntToStr(Trunc(TimerPeriod / OneMillisecond)) + ' ms' + 174 ' ' + IntToStr(Core.Game.Map.CellLinks.Count); 174 175 NewCaption := 'xTactics'; 175 176 if Assigned(Core.Game.CurrentPlayer) then -
trunk/Forms/UFormNew.lfm
r98 r100 49 49 object ListView1: TListView 50 50 Left = 4 51 Height = 36 451 Height = 367 52 52 Top = 4 53 53 Width = 1207 … … 88 88 Left = 224 89 89 Height = 25 90 Top = 37 690 Top = 379 91 91 Width = 83 92 92 Action = APlayerRemove … … 97 97 Left = 16 98 98 Height = 25 99 Top = 37 699 Top = 379 100 100 Width = 83 101 101 Action = APlayerAdd … … 106 106 Left = 120 107 107 Height = 25 108 Top = 37 6108 Top = 379 109 109 Width = 83 110 110 Action = APlayerModify … … 330 330 Caption = 'Image file:' 331 331 ParentColor = False 332 end 333 object CheckBoxBridges: TCheckBox 334 Left = 8 335 Height = 24 336 Top = 310 337 Width = 204 338 Caption = 'Bridges between cells' 339 TabOrder = 14 332 340 end 333 341 end … … 361 369 object Label6: TLabel 362 370 Left = 8 363 Height = 2 5371 Height = 22 364 372 Top = 248 365 Width = 1 29373 Width = 116 366 374 Caption = 'Win objective:' 367 375 ParentColor = False … … 369 377 object ComboBoxWinObjective: TComboBox 370 378 Left = 232 371 Height = 3 3379 Height = 30 372 380 Top = 240 373 381 Width = 328 -
trunk/Forms/UFormNew.lrt
r82 r100 21 21 TFORMNEW.BUTTONIMAGEBROWSE.CAPTION=Browse 22 22 TFORMNEW.LABEL9.CAPTION=Image file: 23 TFORMNEW.CHECKBOXBRIDGES.CAPTION=Bridges between cells 23 24 TFORMNEW.TABSHEET3.CAPTION=Rules 24 25 TFORMNEW.RADIOGROUPGROWCELLS.CAPTION=Growing cells -
trunk/Forms/UFormNew.pas
r91 r100 24 24 ButtonPlayerModify: TButton; 25 25 ButtonPlayerRemove: TButton; 26 CheckBoxBridges: TCheckBox; 26 27 CheckBoxFogOfWar: TCheckBox; 27 28 CheckBoxCity: TCheckBox; … … 354 355 EditImageFile.Text := Game.MapImageFileName; 355 356 CheckBoxFogOfWar.Checked := Game.FogOfWar; 357 CheckBoxBridges.Checked := Game.BridgeEnabled; 356 358 end; 357 359 … … 383 385 Game.MapImageFileName := EditImageFile.Text; 384 386 Game.FogOfWar := CheckBoxFogOfWar.Checked; 387 Game.BridgeEnabled := CheckBoxBridges.Checked; 385 388 end; 386 389 -
trunk/Languages/xtactics.cs.po
r99 r100 267 267 msgstr "Nová hra" 268 268 269 #: tformnew.checkboxbridges.caption 270 msgid "Bridges between cells" 271 msgstr "Mosty mezi buňkami" 272 269 273 #: tformnew.checkboxcity.caption 270 274 msgid "Cities" … … 420 424 #: tformsettings.checkbox2.caption 421 425 msgid "Automatic DPI" 422 msgstr " "426 msgstr "Automatické DPI" 423 427 424 428 #: tformsettings.checkboxdevelmode.caption … … 441 445 #: tformsettings.label4.caption 442 446 msgid "DPI:" 443 msgstr " "447 msgstr "DPI:" 444 448 445 449 #: tformsettings.label5.caption 446 450 msgid "x" 447 msgstr " "451 msgstr "x" 448 452 449 453 #: tformsettings.tabsheetdebug.caption 450 454 msgid "Debug" 451 msgstr " "455 msgstr "Ladění" 452 456 453 457 #: tformsettings.tabsheetgeneral.caption 454 458 msgid "General" 455 msgstr " "459 msgstr "Obecné" 456 460 457 461 #: ucore.sendgame … … 578 582 #: uformplayer.sagronotattacking 579 583 msgid "Not attacking" 580 msgstr " "584 msgstr "Neútočící" 581 585 582 586 #: uformplayer.scomputer … … 627 631 #: ugame.szerozoomnotalowed 628 632 msgid "Zero zoom not allowed" 629 msgstr "" 630 633 msgstr "Nulové přiblížení není povoleno" -
trunk/Languages/xtactics.po
r99 r100 255 255 msgstr "" 256 256 257 #: tformnew.checkboxbridges.caption 258 msgid "Bridges between cells" 259 msgstr "" 260 257 261 #: tformnew.checkboxcity.caption 258 262 msgid "Cities" -
trunk/UCore.pas
r99 r100 359 359 //ApplyToAll(DesignDPI); 360 360 FormNew.Show; 361 FormNew.Hide; 361 362 for I := 0 to Screen.FormCount - 1 do begin 362 363 StoreDimensions(Screen.Forms[I], StoredDimension); 363 364 ScaleDimensions(Screen.Forms[I], StoredDimension); 364 365 end; 365 FormNew.Hide;366 366 ScaleImageList(Core.ImageListSmall, DesignDPI); 367 367 ScaleImageList(Core.ImageListLarge, DesignDPI); -
trunk/UGame.pas
r96 r100 26 26 TCells = class; 27 27 TMap = class; 28 TCellLinks = class; 29 TMapArea = class; 28 30 29 31 TFloatPoint = record … … 39 41 TCell = class 40 42 private 43 FArea: TMapArea; 41 44 FMap: TMap; 42 45 FPower: Integer; 46 procedure SetArea(AValue: TMapArea); 43 47 procedure SetPower(AValue: Integer); 44 48 public … … 54 58 Neighbors: TCells; 55 59 Mark: Boolean; 60 procedure AreaExtend; 56 61 procedure FixRefId; 57 62 procedure LoadFromNode(Node: TDOMNode); … … 66 71 property Power: Integer read FPower write SetPower; 67 72 property Map: TMap read FMap write FMap; 73 property Area: TMapArea read FArea write SetArea; 68 74 end; 69 75 … … 78 84 procedure LoadFromNode(Node: TDOMNode); 79 85 procedure SaveToNode(Node: TDOMNode); 86 procedure ClearMark; 87 end; 88 89 TCellLink = class 90 Points: array of TPoint; 91 Cell1: TCell; 92 Cell2: TCell; 93 end; 94 95 TCellLinks = class(TObjectList) 96 80 97 end; 81 98 … … 116 133 TMapShape = (msRectangle, msImage); 117 134 135 { TMapArea } 136 137 TMapArea = class 138 Id: Integer; 139 Map: TMap; 140 BridgeCount: Integer; 141 Cells: TCells; 142 procedure GetBorderCells(List: TCells); 143 constructor Create; 144 destructor Destroy; override; 145 end; 146 147 TMapAreas = class(TObjectList) 148 149 end; 150 118 151 { TMap } 119 152 … … 136 169 Shape: TMapShape; 137 170 Image: TImage; 171 CellLinks: TCellLinks; 172 Areas: TMapAreas; 138 173 function IsOutsideShape(Coord: TPoint): Boolean; virtual; 139 174 function IsCellsNeighbor(Cell1, Cell2: TCell): Boolean; virtual; … … 357 392 procedure UpdateRepeatMoves(Player: TPlayer); 358 393 procedure CheckCounterMove(Move: TUnitMove); 394 function SearchDifferentCellArea(List: TCells; SourceArea, DestArea: TMapArea): TCell; 395 procedure BuildTerrain; 396 procedure BuildBridges; 397 procedure BuildMapAreas; 359 398 public 360 399 Players: TPlayers; … … 377 416 FileName: string; 378 417 FogOfWar: Boolean; 418 BridgeEnabled: Boolean; 379 419 function AttackProbability(AttackCount, DefendCount: Integer): Double; 380 420 procedure LoadConfig(Config: TXmlConfig; Path: string); … … 499 539 end; 500 540 541 { TMapArea } 542 543 procedure TMapArea.GetBorderCells(List: TCells); 544 var 545 I: Integer; 546 J: Integer; 547 NeighVoidCount: Integer; 548 begin 549 List.Clear; 550 551 // Unset mark for all cells 552 for I := 0 to Map.Cells.Count - 1 do 553 TCell(Map.Cells[I]).Mark := False; 554 555 for I := 0 to Cells.Count - 1 do 556 with TCell(Cells[I]) do begin 557 NeighVoidCount := 0; 558 for J := 0 to Neighbors.Count - 1 do 559 with TCell(Neighbors[J]) do 560 if (Terrain = ttVoid) then Inc(NeighVoidCount); 561 562 if (NeighVoidCount > 0) and (Area = Self) and (not Mark) then begin 563 List.Add(TCell(Self.Cells[I])); 564 Mark := True; 565 end; 566 end; 567 end; 568 569 constructor TMapArea.Create; 570 begin 571 Cells := TCells.Create; 572 Cells.OwnsObjects := False; 573 end; 574 575 destructor TMapArea.Destroy; 576 begin 577 Cells.Free; 578 inherited Destroy; 579 end; 580 501 581 { TPlayerCell } 502 582 … … 641 721 try 642 722 Lock; 723 // Draw cell links 724 Pen.Color := clBlack; 725 Pen.Style := psSolid; 726 Pen.Width := 3; 727 for C := 0 to Player.Game.Map.CellLinks.Count - 1 do 728 with TCellLink(Player.Game.Map.CellLinks[C]) do begin 729 if Length(Points) >= 2 then begin 730 MoveTo(View.CellToCanvasPos(Points[0])); 731 for I := 1 to Length(Points) - 1 do 732 LineTo(View.CellToCanvasPos(Points[I])); 733 end; 734 end; 735 736 // Draw cells 643 737 for C := 0 to Cells.Count - 1 do begin 644 738 Cell := TPlayerCell(Cells[C]); … … 769 863 end; 770 864 865 procedure TCells.ClearMark; 866 var 867 I: Integer; 868 begin 869 for I := 0 to Count - 1 do 870 TCell(Items[I]).Mark := False; 871 end; 872 771 873 { TPlayers } 772 874 … … 957 1059 958 1060 // Generate neighbours 959 for Y := 0 to self.FSize.Y - 1 do1061 for Y := 0 to Self.FSize.Y - 1 do 960 1062 for X := 0 to FSize.X - 1 do 961 1063 with TCell(Cells[Y * FSize.X + X]) do begin … … 1288 1390 I: Integer; 1289 1391 NewCell: TCell; 1290 NeighCells: TCellArray;1291 1392 begin 1292 1393 // Free previous … … 1313 1414 Size := Point(0, 0); 1314 1415 Image := TImage.Create(nil); 1416 CellLinks := TCellLinks.Create; 1417 Areas := TMapAreas.Create; 1315 1418 end; 1316 1419 1317 1420 destructor TMap.Destroy; 1318 1421 begin 1422 Areas.Free; 1423 CellLinks.Free; 1319 1424 Image.Free; 1320 1425 Size := Point(0, 0); … … 1467 1572 raise Exception.Create('Not allowed to substract power under zero do negative value'); 1468 1573 FPower := AValue; 1574 end; 1575 1576 procedure TCell.SetArea(AValue: TMapArea); 1577 begin 1578 if FArea = AValue then Exit; 1579 if Assigned(FArea) then FArea.Cells.Remove(Self); 1580 FArea := AValue; 1581 if Assigned(FArea) then FArea.Cells.Add(Self); 1582 end; 1583 1584 procedure TCell.AreaExtend; 1585 var 1586 I: Integer; 1587 begin 1588 for I := 0 to Neighbors.Count - 1 do 1589 with TCell(Neighbors[I]) do 1590 if (Terrain <> ttVoid) and (not Assigned(Area)) then begin 1591 Area := Self.Area; 1592 AreaExtend; 1593 end; 1469 1594 end; 1470 1595 … … 2385 2510 end; 2386 2511 2512 function TGame.SearchDifferentCellArea(List: TCells; SourceArea, DestArea: TMapArea): TCell; 2513 var 2514 NewList: TCells; 2515 NewListVoid: TCells; 2516 I: Integer; 2517 C: Integer; 2518 begin 2519 Result := nil; 2520 NewList := TCells.Create; 2521 NewList.OwnsObjects := False; 2522 NewListVoid := TCells.Create; 2523 NewListVoid.OwnsObjects := False; 2524 2525 for C := 0 to List.Count - 1 do 2526 with TCell(List[C]) do begin 2527 for I := 0 to Neighbors.Count - 1 do 2528 with TCell(Neighbors[I]) do 2529 if (not Mark) and (Terrain <> ttVoid) and (Area <> SourceArea) and ((DestArea = nil) or (DestArea = Area)) then begin 2530 NewList.Add(TCell(TCell(List[C]).Neighbors[I])); 2531 Mark := True; 2532 end else 2533 if (not Mark) and (Terrain = ttVoid) then begin 2534 NewListVoid.Add(TCell(TCell(List[C]).Neighbors[I])); 2535 Mark := True; 2536 end; 2537 end; 2538 2539 if NewList.Count > 0 then begin 2540 // We found cell with different area 2541 Result := TCell(NewList[Random(NewList.Count)]); 2542 end else 2543 if NewListVoid.Count > 0 then begin 2544 // Cell was not found but we have more void cells to check 2545 Result := SearchDifferentCellArea(NewListVoid, SourceArea, DestArea); 2546 end; 2547 2548 NewListVoid.Free; 2549 NewList.Free; 2550 end; 2551 2552 procedure TGame.BuildTerrain; 2553 var 2554 C: Integer; 2555 begin 2556 if (Map.Shape = msImage) and FileExists(MapImageFileName) and 2557 (LoadedImageFileName <> MapImageFileName) then begin 2558 LoadedImageFileName := MapImageFileName; 2559 Map.Image.Picture.LoadFromFile(MapImageFileName); 2560 end; 2561 2562 // Randomize map terrain 2563 for C := 0 to Map.Cells.Count - 1 do 2564 with TCell(Map.Cells[C]) do begin 2565 if (VoidEnabled and (Random < VoidPercentage / 100)) or 2566 (Map.IsOutsideShape(PosPx)) then Terrain := ttVoid 2567 else begin 2568 if CityEnabled and (Random < CityPercentage / 100) then Terrain := ttCity 2569 else Terrain := ttNormal; 2570 end; 2571 Power := Random(MaxNeutralUnits + 1); 2572 Player := nil; 2573 end; 2574 end; 2575 2576 procedure TGame.BuildBridges; 2577 var 2578 List: TCells; 2579 Cell: TCell; 2580 FoundCell1: TCell; 2581 FoundCell2: TCell; 2582 I: Integer; 2583 J: Integer; 2584 NewLink: TCellLink; 2585 begin 2586 // Build area bridges 2587 if Map.Areas.Count > 1 then 2588 for I := 0 to Map.Areas.Count - 1 do 2589 with TMapArea(Map.Areas[I]) do begin 2590 List := TCells.Create; 2591 List.OwnsObjects := False; 2592 GetBorderCells(List); 2593 Cell := TCell(List[Random(List.Count)]); 2594 List.Clear; 2595 List.Add(Cell); 2596 2597 Map.Cells.ClearMark; 2598 2599 // Find nearest cell with different area 2600 FoundCell1 := SearchDifferentCellArea(List, TMapArea(Map.Areas[I]), nil); 2601 if Assigned(FoundCell1) then begin 2602 // Again find back nearest cell with different area. 2603 // This will ensure that both cells are closest ones 2604 2605 Map.Cells.ClearMark; 2606 List[0] := FoundCell1; 2607 FoundCell2 := SearchDifferentCellArea(List, FoundCell1.Area, TMapArea(Map.Areas[I])); 2608 if Assigned(FoundCell2) then begin 2609 FoundCell1.Neighbors.Add(FoundCell2); 2610 FoundCell2.Neighbors.Add(FoundCell1); 2611 NewLink := TCellLink.Create; 2612 SetLength(NewLink.Points, 2); 2613 NewLink.Cell1 := FoundCell2; 2614 NewLink.Points[0] := FoundCell2.PosPx; 2615 NewLink.Cell2 := FoundCell1; 2616 NewLink.Points[1] := FoundCell1.PosPx; 2617 Map.CellLinks.Add(NewLink); 2618 Inc(BridgeCount); 2619 end; 2620 end; 2621 2622 List.Free; 2623 end; 2624 end; 2625 2626 procedure TGame.BuildMapAreas; 2627 var 2628 C: Integer; 2629 NewArea: TMapArea; 2630 begin 2631 for C := 0 to Map.Cells.Count - 1 do 2632 with TCell(Map.Cells[C]) do 2633 Area := nil; 2634 Map.Areas.Clear; 2635 for C := 0 to Map.Cells.Count - 1 do 2636 with TCell(Map.Cells[C]) do 2637 if (Terrain <> ttVoid) and (not Assigned(Area)) then begin 2638 NewArea := TMapArea(Map.Areas[Map.Areas.Add(TMapArea.Create)]); 2639 NewArea.Id := Map.Areas.Count; 2640 NewArea.Map := Map; 2641 Area := NewArea; 2642 AreaExtend; 2643 end; 2644 end; 2645 2387 2646 procedure TGame.SaveConfig(Config: TXmlConfig; Path: string); 2388 2647 begin … … 2399 2658 SetValue(Path + '/CityEnabled', CityEnabled); 2400 2659 SetValue(Path + '/CityPercentage', CityPercentage); 2660 SetValue(Path + '/BridgeEnabled', BridgeEnabled); 2401 2661 SetValue(Path + '/GrowAmount', Integer(GrowAmount)); 2402 2662 SetValue(Path + '/GrowCells', Integer(GrowCells)); … … 2421 2681 CityEnabled := GetValue(Path + '/CityEnabled', False); 2422 2682 CityPercentage := GetValue(Path + '/CityPercentage', 10); 2683 BridgeEnabled := GetValue(Path + '/BridgeEnabled', True); 2423 2684 GrowAmount := TGrowAmount(GetValue(Path + '/GrowAmount', Integer(gaBySquareRoot))); 2424 2685 GrowCells := TGrowCells(GetValue(Path + '/GrowCells', Integer(gcPlayerAll))); … … 2450 2711 CityEnabled := ReadBoolean(RootNode, 'CityEnabled', False); 2451 2712 CityPercentage := ReadInteger(RootNode, 'CityPercentage', 0); 2713 BridgeEnabled := ReadBoolean(RootNode, 'BridgeEnabled', False); 2452 2714 TurnCounter := ReadInteger(RootNode, 'TurnCounter', 0); 2453 2715 WinObjective := TWinObjective(ReadInteger(RootNode, 'WinObjective', Integer(woDefeatAllOponents))); … … 2503 2765 WriteBoolean(RootNode, 'CityEnabled', CityEnabled); 2504 2766 WriteInteger(RootNode, 'CityPercentage', CityPercentage); 2767 WriteBoolean(RootNode, 'BridgeEnabled', BridgeEnabled); 2505 2768 WriteInteger(RootNode, 'TurnCounter', TurnCounter); 2506 2769 WriteInteger(RootNode, 'WinObjective', Integer(WinObjective)); … … 2655 2918 Counter: Integer; 2656 2919 C: Integer; 2920 LastAreaCount: Integer; 2657 2921 begin 2658 2922 FileName := SNewGameFile; 2659 2923 TurnCounter := 1; 2660 2924 Moves.Clear; 2661 if (Map.Shape = msImage) and FileExists(MapImageFileName) and 2662 (LoadedImageFileName <> MapImageFileName) then begin 2663 LoadedImageFileName := MapImageFileName; 2664 Map.Image.Picture.LoadFromFile(MapImageFileName); 2665 end; 2666 for C := 0 to Map.Cells.Count - 1 do 2667 with TCell(Map.Cells[C]) do begin 2668 if (VoidEnabled and (Random < VoidPercentage / 100)) or 2669 (Map.IsOutsideShape(PosPx)) then Terrain := ttVoid 2670 else begin 2671 if CityEnabled and (Random < CityPercentage / 100) then Terrain := ttCity 2672 else Terrain := ttNormal; 2673 end; 2674 Power := Random(MaxNeutralUnits + 1); 2675 Player := nil; 2925 2926 BuildTerrain; 2927 if BridgeEnabled then begin 2928 // Connect all areas to all cells be accessible 2929 for I := 0 to Map.CellLinks.Count - 1 do 2930 with TCellLink(Map.CellLinks[I]) do begin 2931 Cell1.Neighbors.Remove(Cell2); 2932 Cell2.Neighbors.Remove(Cell1); 2933 end; 2934 Map.CellLinks.Clear; 2935 BuildMapAreas; 2936 LastAreaCount := -1; 2937 while (Map.Areas.Count > 1) and (Map.Areas.Count <> LastAreaCount) do begin 2938 LastAreaCount := Map.Areas.Count; 2939 BuildBridges; 2940 BuildMapAreas; 2941 end; 2676 2942 end; 2677 2943 … … 2819 3085 try 2820 3086 Lock; 3087 3088 // Draw cell links 3089 Pen.Color := clBlack; 3090 Pen.Style := psSolid; 3091 Pen.Width := 3; 3092 for C := 0 to CellLinks.Count - 1 do 3093 with TCellLink(CellLinks[C]) do begin 3094 if Length(Points) >= 2 then begin 3095 MoveTo(Points[0]); 3096 for I := 1 to Length(Points) - 1 do 3097 LineTo(Points[I]); 3098 end; 3099 end; 3100 3101 // Draw cells 2821 3102 for C := 0 to Cells.Count - 1 do begin 2822 3103 Cell := TCell(Cells[C]);
Note:
See TracChangeset
for help on using the changeset viewer.